/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012 gnosygnu@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package gplx.dbs.qrys; import gplx.*; import gplx.dbs.*; import gplx.core.brys.fmtrs.*; import gplx.core.stores.*; import gplx.dbs.engines.*; public class Db_stmt_sql implements Db_stmt {// used for formatting SQL statements; not used for actual insert into database private static final String Key_na = ""; // key is not_available; only called by procs with signature of Val( v); private final List_adp args = List_adp_.new_(); private final Bry_bfr tmp_bfr = Bry_bfr.new_(); private final Bry_fmtr tmp_fmtr = Bry_fmtr.new_(); public void Ctor_stmt(Db_engine engine, Db_qry qry) {} public Db_conn Conn() {return conn;} public void Conn_(Db_conn v) {this.conn = v;} Db_conn conn; public Db_stmt Reset_stmt() {return this;} public Db_stmt Crt_bool_as_byte(String k, boolean v) {return Add_byte_by_bool(Bool_.Y, k, v);} public Db_stmt Val_bool_as_byte(String k, boolean v) {return Add_byte_by_bool(Bool_.N, k, v);} public Db_stmt Val_bool_as_byte(boolean v) {return Add_byte_by_bool(Bool_.N, Key_na, v);} private Db_stmt Add_byte_by_bool(boolean where, String k, boolean v) {return Add_byte(where, k, v ? Bool_.Y_byte : Bool_.N_byte);} public Db_stmt Crt_byte(String k, byte v) {return Add_byte(Bool_.Y, k, v);} public Db_stmt Val_byte(String k, byte v) {return Add_byte(Bool_.N, k, v);} public Db_stmt Val_byte(byte v) {return Add_byte(Bool_.N, Key_na, v);} private Db_stmt Add_byte(boolean where, String k, byte v) { try {Add(k, Byte_.To_str(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "byte", "val", v);} return this; } public Db_stmt Crt_int(String k, int v) {return Add_int(Bool_.Y, k, v);} public Db_stmt Val_int_by_bool(String k, boolean v) {return Add_int(Bool_.N, k, v ? 1 : 0);} public Db_stmt Val_int(String k, int v) {return Add_int(Bool_.N, k, v);} public Db_stmt Val_int(int v) {return Add_int(Bool_.N, Key_na, v);} private Db_stmt Add_int(boolean where, String k, int v) { try {Add(k, Int_.To_str(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "int", "val", v);} return this; } public Db_stmt Crt_long(String k, long v) {return Add_long(Bool_.Y, k, v);} public Db_stmt Val_long(String k, long v) {return Add_long(Bool_.N, k, v);} public Db_stmt Val_long(long v) {return Add_long(Bool_.N, Key_na, v);} private Db_stmt Add_long(boolean where, String k, long v) { try {Add(k, Long_.To_str(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "long", "val", v);} return this; } public Db_stmt Crt_float(String k, float v) {return Add_float(Bool_.Y, k, v);} public Db_stmt Val_float(String k, float v) {return Add_float(Bool_.N, k, v);} public Db_stmt Val_float(float v) {return Add_float(Bool_.N, Key_na, v);} private Db_stmt Add_float(boolean where, String k, float v) { try {Add(k, Float_.To_str(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "float", "val", v);} return this; } public Db_stmt Crt_double(String k, double v) {return Add_double(Bool_.Y, k, v);} public Db_stmt Val_double(String k, double v) {return Add_double(Bool_.N, k, v);} public Db_stmt Val_double(double v) {return Add_double(Bool_.N, Key_na, v);} private Db_stmt Add_double(boolean where, String k, double v) { try {Add(k, Double_.To_str(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "double", "val", v);} return this; } public Db_stmt Crt_decimal(String k, Decimal_adp v) {return Add_decimal(Bool_.Y, k, v);} public Db_stmt Val_decimal(String k, Decimal_adp v) {return Add_decimal(Bool_.N, k, v);} public Db_stmt Val_decimal(Decimal_adp v) {return Add_decimal(Bool_.N, Key_na, v);} private Db_stmt Add_decimal(boolean where, String k, Decimal_adp v) { try {Add(k, v.To_str());} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "decimal", "val", v);} return this; } public Db_stmt Crt_bry(String k, byte[] v) {return Add_bry(Bool_.Y, k, v);} public Db_stmt Val_bry(String k, byte[] v) {return Add_bry(Bool_.N, k, v);} public Db_stmt Val_bry(byte[] v) {return Add_bry(Bool_.N, Key_na, v);} private Db_stmt Add_bry(boolean where, String k, byte[] v) {// HACK: convert to String b/c tdb does not support byte[] try {Add(k, Val_str_wrap(String_.new_u8(v)));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "byte[]", "val", v.length);} return this; } public Db_stmt Crt_bry_as_str(String k, byte[] v) {return Add_bry_as_str(Bool_.Y, k, v);} public Db_stmt Val_bry_as_str(String k, byte[] v) {return Add_bry_as_str(Bool_.N, k, v);} public Db_stmt Val_bry_as_str(byte[] v) {return Add_bry_as_str(Bool_.N, Key_na, v);} private Db_stmt Add_bry_as_str(boolean where, String k, byte[] v) {return Add_str(where, k, String_.new_u8(v));} public Db_stmt Crt_str(String k, String v) {return Add_str(Bool_.Y, k, v);} public Db_stmt Val_str(String k, String v) {return Add_str(Bool_.N, k, v);} public Db_stmt Val_str(String v) {return Add_str(Bool_.N, Key_na, v);} private Db_stmt Add_str(boolean where, String k, String v) { try {Add(k, Val_str_wrap(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "String", "val", v);} return this; } public Db_stmt Crt_date(String k, DateAdp v) {return Add_date(Bool_.Y, k, v);} public Db_stmt Val_date(String k, DateAdp v) {return Add_date(Bool_.N, k, v);} private Db_stmt Add_date(boolean where, String k, DateAdp v) { try {Add(k, Val_str_wrap(v.XtoStr_fmt_iso_8561()));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "date", "val", v);} return this; } public Db_stmt Crt_text(String k, String v) {return Add_text(Bool_.Y, k, v);} public Db_stmt Val_text(String k, String v) {return Add_text(Bool_.N, k, v);} private Db_stmt Add_text(boolean where, String k, String v) { try {Add(k, Val_str_wrap(v));} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "text", "val", v);} return this; } public Db_stmt Val_rdr_(gplx.core.ios.Io_stream_rdr v, long rdr_len) { try { Bry_bfr bfr = Bry_bfr.new_(); gplx.core.ios.Io_stream_rdr_.Load_all_to_bfr(bfr, v); Add(Key_na, bfr.To_str_and_clear()); } catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "rdr", "val", v);} return this; } private String Val_str_wrap(String v) { return "'" + String_.Replace(v, "'", "\\'") + "'"; } public boolean Exec_insert() { try {boolean rv = conn.Exec_qry(Db_qry_sql.dml_(this.Xto_sql())) != 0; return rv;} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to exec prepared statement", "sql", sql_orig);} } public int Exec_update() { try {int rv = conn.Exec_qry(Db_qry_sql.dml_(this.Xto_sql())); return rv;} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to exec prepared statement", "sql", sql_orig);} } public int Exec_delete() { try {int rv = conn.Exec_qry(Db_qry_sql.dml_(this.Xto_sql())); return rv;} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to exec prepared statement", "sql", sql_orig);} } public DataRdr Exec_select() { try {DataRdr rv = conn.Exec_qry_as_old_rdr(Db_qry_sql.rdr_(this.Xto_sql())); return rv;} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to exec prepared statement", "sql", sql_orig);} } public Db_rdr Exec_select__rls_auto() {return Db_rdr_.Empty;} public Db_rdr Exec_select__rls_manual() {return Db_rdr_.Empty;} public Object Exec_select_val() { try {Object rv = DataRdr_.Read_1st_row_and_1st_fld(this.Exec_select()); return rv;} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to exec prepared statement", "sql", sql_orig);} } public Db_stmt Clear() { args.Clear(); return this; } public void Rls() {this.Clear();} public void Add(String k, String v) { if (k == Dbmeta_fld_itm.Key_null) return; // key is explicitly null; ignore; allows version_2+ type definitions args.Add(v); } public String Xto_sql() { tmp_fmtr.Bld_bfr_many(tmp_bfr, (Object[])args.To_ary_and_clear(Object.class)); return tmp_bfr.To_str_and_clear(); } public int Args_len() {return args.Count();} public String Args_get_at(int i) {return (String)args.Get_at(i);} private String sql_orig; public Db_qry Qry() {return qry;} private Db_qry qry; public Db_stmt Parse(Db_qry qry, String sql_str) { this.qry = qry; this.sql_orig = sql_str; Init_fmtr(tmp_bfr, tmp_fmtr, sql_str); return this; } private static void Init_fmtr(Bry_bfr tmp_bfr, Bry_fmtr tmp_fmtr, String sql_str) { byte[] sql_bry = Bry_.new_u8(sql_str); int arg_idx = 0; int pos_prv = 0; tmp_bfr.Clear(); while (true) { int pos_cur = Bry_find_.Find_fwd(sql_bry, Byte_ascii.Question, pos_prv); if (pos_cur == Bry_find_.Not_found) break; tmp_bfr.Add_mid(sql_bry, pos_prv, pos_cur); tmp_bfr.Add_byte(Byte_ascii.Tilde).Add_byte(Byte_ascii.Curly_bgn); tmp_bfr.Add_int_variable(arg_idx++); tmp_bfr.Add_byte(Byte_ascii.Curly_end); pos_prv = pos_cur + 1; } tmp_bfr.Add_mid(sql_bry, pos_prv, sql_bry.length); tmp_fmtr.Fmt_(tmp_bfr.To_bry_and_clear()); } public static String Xto_str(Bry_bfr tmp_bfr, Bry_fmtr tmp_fmtr, String sql_str, List_adp args) { Init_fmtr(tmp_bfr, tmp_fmtr, sql_str); Object[] ary = args.To_obj_ary(); int len = ary.length; for (int i = 0; i < len; ++i) { Object obj = ary[i]; String str = ""; if (obj == null) str = "NULL"; else { str = Object_.Xto_str_strict_or_null(obj); if (Type_adp_.Eq(obj.getClass(), String_.Cls_ref_type)) str = "'" + String_.Replace(str, "'", "''") + "'"; } ary[i] = str; } tmp_fmtr.Bld_bfr_many(tmp_bfr, ary); return tmp_bfr.To_str_and_clear(); } }