/* ************************************************************************ # # DivConq # # http://divconq.com/ # # Copyright: # Copyright 2014 eTimeline, LLC. All rights reserved. # # License: # See the license.txt file in the project's top-level directory for details. # # Authors: # * Andy White # ************************************************************************ */ package divconq.script.inst.sql; import java.util.Arrays; import java.util.List; import divconq.hub.Hub; import divconq.lang.StringBuilder32; import divconq.lang.op.FuncResult; import divconq.lang.op.OperationContext; import divconq.script.ExecuteState; import divconq.script.Instruction; import divconq.script.StackEntry; import divconq.sql.SqlManager.SqlDatabase; import divconq.sql.SqlNull; import divconq.util.StringUtil; import divconq.xml.XElement; public class SqlUpdate extends Instruction { @Override public void run(final StackEntry stack) { //OperationContext.get().info("Doing a SQL UPDATE on thread " + Thread.currentThread().getName()); String dbname = stack.stringFromSource("Database", "default"); String table = stack.stringFromSource("Table"); if (StringUtil.isEmpty(dbname) || StringUtil.isEmpty(table)) { OperationContext.get().error("Missing table for insert"); stack.setState(ExecuteState.Done); stack.resume(); return; } XElement codeEl = stack.getInstruction().getXml(); StringBuilder32 sb1 = new StringBuilder32(); sb1.append("UPDATE " + table + " SET "); List<XElement> fields = codeEl.selectAll("Field"); XElement el2 = codeEl.selectFirst("Where"); if (el2 == null) { OperationContext.get().error("Missing WHERE in SQL UPDATE"); stack.setState(ExecuteState.Done); stack.resume(); return; } boolean firstfld = true; int pos = 0; Object[] vals = new Object[fields.size() + ((el2 == null) ? 0 : 1)]; for (XElement el : fields) { boolean skipnull = stack.boolFromElement(el, "SkipNull", false); Object val = SqlInsert.convertValueToInternal(stack, el); if (skipnull && (val instanceof SqlNull)) continue; if (firstfld) firstfld = false; else sb1.append(','); sb1.append(stack.stringFromElement(el, "Name") + " = ?"); vals[pos] = val; pos++; } vals[pos] = SqlInsert.convertValueToInternal(stack, el2); pos++; // if too big, resize array if (pos < vals.length) vals = Arrays.copyOfRange(vals, 0, pos); // no fields updated - don't error, might just mean there was no match after skip checks if (firstfld) { stack.setState(ExecuteState.Done); stack.resume(); return; } String sql = sb1.toString() + " WHERE " + stack.stringFromElement(el2, "Name") + " = ?"; SqlDatabase db = Hub.instance.getSQLDatabase(dbname); if (db == null) { OperationContext.get().errorTr(185, dbname); stack.setState(ExecuteState.Done); stack.resume(); return; } FuncResult<Integer> rsres = db.executeUpdate(sql, vals); if (rsres.getResult() != 1) OperationContext.get().error("UPDATE failed, expected 1 row result count"); stack.setState(ExecuteState.Done); stack.resume(); } @Override public void cancel(StackEntry stack) { // do nothing, this isn't cancellable } }