/* ************************************************************************ # # 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.math.BigDecimal; import java.util.List; import org.joda.time.DateTime; 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.sql.SqlType; import divconq.struct.Struct; import divconq.struct.scalar.NullStruct; import divconq.util.StringUtil; import divconq.xml.XElement; public class SqlInsert extends Instruction { @Override public void run(StackEntry stack) { //OperationContext.get().info("Doing a SQL INSERT 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("INSERT INTO " + table + " ("); StringBuilder32 sb2 = new StringBuilder32(); sb2.append(" VALUES ("); List<XElement> fields = codeEl.selectAll("Field"); boolean firstfld = true; Object[] vals = new Object[fields.size()]; int pos = 0; for (XElement el : fields) { if (firstfld) firstfld = false; else { sb1.append(','); sb2.append(','); } sb1.append(stack.stringFromElement(el, "Name")); sb2.append('?'); vals[pos] = SqlInsert.convertValueToInternal(stack, el); pos++; } sb1.append(')'); sb2.append(')'); // no fields found if (firstfld) { stack.setState(ExecuteState.Done); stack.resume(); return; } String sql = sb1.toString() + sb2.toString(); 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.executeInsert(sql, vals); if (rsres.getResult() != 1) OperationContext.get().error("INSERT failed, expected 1 row result count"); stack.setState(ExecuteState.Done); stack.resume(); } @Override public void cancel(StackEntry stack) { // do nothing, this isn't cancellable } static public Object convertValueToInternal(StackEntry stack, XElement el) { String ftype = stack.stringFromElement(el, "Type"); Struct dt = stack.refFromElement(el, "Value"); SqlType stype = SqlType.valueOf(ftype); if (stype == SqlType.Int) { Long ret = Struct.objectToInteger(dt); return (ret == null) ? SqlNull.Int : ret; } if (stype == SqlType.Long) { Long ret = Struct.objectToInteger(dt); return (ret == null) ? SqlNull.Long : ret; } if (stype == SqlType.Double) { BigDecimal ret = Struct.objectToDecimal(dt); return (ret == null) ? SqlNull.Double : ret; } if (stype == SqlType.BigDecimal) { BigDecimal ret = Struct.objectToDecimal(dt); return (ret == null) ? SqlNull.BigDecimal : ret; } if (stype == SqlType.DateTime) { DateTime ret = Struct.objectToDateTime(dt); return (ret == null) ? SqlNull.DateTime : ret; } if (stype == SqlType.Text) { if (dt == NullStruct.instance) return SqlNull.Text; String ret = Struct.objectToString(dt); if (ret == null) return SqlNull.Text; if ("True".equals(stack.stringFromElement(el, "Encrypt"))) ret = Hub.instance.getClock().getObfuscator().encryptStringToHex(ret); return ret; } if (dt == NullStruct.instance) return SqlNull.VarChar; String ret = Struct.objectToString(dt); if (ret == null) return SqlNull.VarChar; if ("True".equals(stack.stringFromElement(el, "Encrypt"))) ret = Hub.instance.getClock().getObfuscator().encryptStringToHex(ret); return ret; } }