/* 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.engines; import gplx.*; import gplx.dbs.*; import java.sql.*; import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.metas.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.*; import gplx.dbs.sqls.wtrs.*; public abstract class Db_engine_sql_base implements Db_engine { @gplx.Internal protected void Ctor(Db_conn_info conn_info) {this.conn_info = conn_info;} public abstract String Tid(); public Db_conn_info Conn_info() {return conn_info;} protected Db_conn_info conn_info; public abstract Sql_qry_wtr Sql_wtr(); public abstract Db_engine New_clone(Db_conn_info conn_info); public Db_rdr New_rdr__rls_manual(Object rdr_obj, String sql) {return New_rdr(null, rdr_obj, sql);} public Db_rdr New_rdr__rls_auto(Db_stmt stmt, Object rdr_obj, String sql) {return New_rdr(stmt, rdr_obj, sql);} @gplx.Virtual public Db_rdr New_rdr_clone() {return new Db_rdr__basic();} @gplx.Virtual public Db_stmt New_stmt_prep(Db_qry qry) {return new Db_stmt_cmd(this, qry);} @gplx.Virtual public void Txn_bgn(String name) {Exec_as_obj(Db_qry_sql.xtn_("BEGIN TRANSACTION;"));} @gplx.Virtual public String Txn_end() {Exec_as_obj(Db_qry_sql.xtn_("COMMIT TRANSACTION;")); return "";} @gplx.Virtual public void Txn_cxl() {Exec_as_obj(Db_qry_sql.xtn_("ROLLBACK TRANSACTION;"));} @gplx.Virtual public void Txn_sav() { String txn_name = this.Txn_end(); this.Txn_bgn(txn_name); } public Object Exec_as_obj(Db_qry qry) { if (qry.Tid() == Db_qry_.Tid_flush) return null; // ignore flush (delete-db) statements String sql = this.Sql_wtr().To_sql_str(qry, false); // DBG: Tfds.Write(sql); return qry.Exec_is_rdr() ? (Object)this.Exec_as_rdr(sql) : this.Exec_as_int(sql); } protected int Exec_as_int(String sql) { try { Statement cmd = New_stmt_exec(sql); return cmd.executeUpdate(sql); } catch (Exception e) {throw Err_.new_exc(e, "db", "db.engine:exec failed", "url", conn_info.Xto_api(), "sql", sql);} } private DataRdr Exec_as_rdr(String sql) { try { Statement cmd = New_stmt_exec(sql); cmd.execute(sql); ResultSet rdr = cmd.getResultSet(); return New_rdr(rdr, sql); } catch (Exception e) {throw Err_.new_exc(e, "db", "db.engine:rdr failed", "url", conn_info.Xto_api(), "sql", sql);} } public void Ddl_create_tbl(Dbmeta_tbl_itm tbl) {Exec_as_int(tbl.To_sql_create(this.Sql_wtr()));} public void Ddl_create_idx(Gfo_usr_dlg usr_dlg, Dbmeta_idx_itm... ary) { int len = ary.length; for (int i = 0; i < len; ++i) { Dbmeta_idx_itm idx = ary[i]; usr_dlg.Plog_many("", "", "creating database index (please wait); db=~{0} idx=~{1}", conn_info.Database(), idx.Name()); Exec_as_int(idx.To_sql_create(Sql_wtr())); } } public void Ddl_append_fld(String tbl, Dbmeta_fld_itm fld) { Gfo_usr_dlg_.Instance.Plog_many("", "", "adding column to table: db=~{0} tbl=~{1} fld=~{2}", conn_info.Database(), tbl, fld.Name()); try { Exec_as_int(this.Sql_wtr().Schema_wtr().Bld_alter_tbl_add(tbl, fld)); Gfo_usr_dlg_.Instance.Plog_many("", "", "column added to table: db=~{0} tbl=~{1} fld=~{2}", conn_info.Database(), tbl, fld.Name()); } catch (Exception e) { // catch error if column already added to table Gfo_usr_dlg_.Instance.Warn_many("", "", "column not added to table: db=~{0} tbl=~{1} fld=~{2} err=~{3}", conn_info.Database(), tbl, fld.Name(), Err_.Message_gplx_full(e)); } } public void Ddl_delete_tbl(String tbl) {Exec_as_int(this.Sql_wtr().Schema_wtr().Bld_drop_tbl(tbl));} @gplx.Virtual public void Env_db_attach(String alias, Io_url db_url) {} @gplx.Virtual public void Env_db_detach(String alias) {} @gplx.Virtual public boolean Meta_tbl_exists(String tbl) {return false;} @gplx.Virtual public boolean Meta_fld_exists(String tbl, String fld) {return false;} public abstract Dbmeta_tbl_mgr Meta_tbl_load_all(); @gplx.Virtual public DataRdr New_rdr(ResultSet rdr, String sql) {return gplx.core.stores.Db_data_rdr_.new_(rdr, sql);} private Db_rdr New_rdr(Db_stmt stmt, Object rdr, String sql) { Db_rdr__basic rv = (Db_rdr__basic)New_rdr_clone(); rv.Ctor(stmt, (ResultSet)rdr, sql); return rv; } @gplx.Internal protected abstract Connection Conn_new(); protected Connection connection; public void Conn_open() {connection = Conn_new();} public void Conn_term() { if (connection == null) return; // connection never opened; just exit try {connection.close();} catch (Exception e) {throw Err_.new_exc(e, "db", "Conn_term failed", "url", conn_info.Xto_raw());} connection = null; } public Object New_stmt_prep_as_obj(String sql) { if (connection == null) connection = Conn_new(); // auto-open connection try {return connection.prepareStatement(sql);} catch (Exception e) {throw Err_.new_exc(e, "db", "New_stmt_prep failed", "sql", sql);} } private Statement New_stmt_exec(String sql) { if (connection == null) connection = Conn_new(); // auto-open connection try {return connection.createStatement();} catch (Exception e) {throw Err_.new_exc(e, "db", "New_stmt_exec failed", "sql", sql);} } protected Connection Conn_make_by_url(String url, String uid, String pwd) { try {return DriverManager.getConnection(url, uid, pwd);} catch (SQLException e) {throw Err_.new_exc(e, "db", "connection open failed", "info", Conn_info().Xto_raw());} } }