1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

Source: Restore broken commit

This commit is contained in:
gnosygnu
2017-02-06 22:14:55 -05:00
parent 938beac9f9
commit 3bfeb94b43
4380 changed files with 328018 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines; import gplx.*; import gplx.dbs.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
public interface Db_engine {
String Tid();
Db_conn_info Conn_info();
Db_conn_props_mgr Props();
Db_batch_mgr Batch_mgr();
Sql_qry_wtr Sql_wtr();
Db_engine New_clone(Db_conn_info conn_info);
void Conn_open();
void Conn_term();
void Txn_bgn(String name); // NOTE: sqlite has different transaction semantics with SAVEPOINT
String Txn_end();
void Txn_cxl();
void Txn_sav();
void Meta_tbl_create(Dbmeta_tbl_itm meta);
void Meta_tbl_delete(String tbl);
void Meta_fld_append(String tbl, Dbmeta_fld_itm fld);
void Meta_idx_create(Gfo_usr_dlg usr_dlg, Dbmeta_idx_itm... ary);
void Meta_idx_delete(String idx);
Dbmeta_tbl_mgr Meta_mgr();
boolean Meta_tbl_exists(String tbl);
boolean Meta_fld_exists(String tbl, String fld);
boolean Meta_idx_exists(String idx);
Object Exec_as_obj(Db_qry qry);
Db_rdr Exec_as_rdr__rls_manual (Object rdr_obj, String sql); // Object o:ResultSet if desktop; Cursor if android
Db_rdr Exec_as_rdr__rls_auto (Db_stmt stmt, Object rdr_obj, String sql); // Object o:ResultSet if desktop; Cursor if android
Db_stmt Stmt_by_qry(Db_qry qry);
Object Stmt_by_sql(String sql);
void Env_db_attach(String alias, Db_conn conn);
void Env_db_attach(String alias, Io_url db_url);
void Env_db_detach(String alias);
DataRdr New_rdr(java.sql.ResultSet rdr, String sql);
}

View File

@@ -0,0 +1,141 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
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.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
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 Db_conn_props_mgr Props() {return props;} private final Db_conn_props_mgr props = new Db_conn_props_mgr();
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public abstract Sql_qry_wtr Sql_wtr();
public abstract Db_engine New_clone(Db_conn_info conn_info);
public Db_rdr Exec_as_rdr__rls_manual(Object rdr_obj, String sql) {return New_rdr(null, rdr_obj, sql);}
public Db_rdr Exec_as_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 Stmt_by_qry(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;")); batch_mgr.Txn_end().Run(this); 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.Db_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.Db_api(), "sql", sql);}
}
public void Meta_tbl_create(Dbmeta_tbl_itm tbl) {Exec_as_int(tbl.To_sql_create(this.Sql_wtr())); this.Meta_mgr().Load_all();}
public void Meta_tbl_delete(String tbl) {Exec_as_int(this.Sql_wtr().Schema_wtr().Bld_drop_tbl(tbl)); this.Meta_mgr().Load_all();}
public void Meta_idx_create(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 db index (please wait); db=~{0} idx=~{1}", conn_info.Database(), idx.Name());
Exec_as_int(idx.To_sql_create(Sql_wtr()));
}
this.Meta_mgr().Load_all();
}
@gplx.Virtual public void Meta_idx_delete(String idx) {
if (Meta_idx_exists(idx)) Exec_as_int("DROP INDEX " + idx);
}
public void Meta_fld_append(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));
}
this.Meta_mgr().Load_all();
}
@gplx.Virtual public boolean Meta_tbl_exists(String tbl) {return false;}
@gplx.Virtual public boolean Meta_fld_exists(String tbl, String fld) {return false;}
@gplx.Virtual public boolean Meta_idx_exists(String idx) {return false;}
public abstract Dbmeta_tbl_mgr Meta_mgr();
@gplx.Virtual public void Env_db_attach(String alias, Io_url db_url) {}
@gplx.Virtual public void Env_db_attach(String alias, Db_conn db_url) {}
@gplx.Virtual public void Env_db_detach(String alias) {}
@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_make();
private void Batch_mgr__conn_bgn() {batch_mgr.Conn_bgn().Run(this);}
private void Batch_mgr__conn_end() {batch_mgr.Conn_end().Run(this);}
private void Conn_assert() {
this.connection = Conn_make(); // auto-open connection
Batch_mgr__conn_bgn();
}
protected Connection connection;
public void Conn_open() {connection = Conn_make();}
public void Conn_term() {
if (connection == null) return; // connection never opened; just exit
this.Batch_mgr__conn_end();
try {connection.close();}
catch (Exception e) {throw Err_.new_exc(e, "db", "Conn_term failed", "url", conn_info.Raw());}
connection = null;
}
@Override public Object Stmt_by_sql(String sql) {
if (connection == null) Conn_assert();
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) Conn_assert();
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().Raw());}
}
protected Connection Conn__new_by_url_and_props(String url, Keyval... props) {
try {
java.util.Properties properties = new java.util.Properties();
for (Keyval prop : props)
properties.setProperty(prop.Key(), prop.Val_to_str_or_empty());
return DriverManager.getConnection(url, properties);
}
catch (SQLException e) {throw Err_.new_exc(e, "db", "connection open failed", "info", Conn_info().Raw());}
}
}

View File

@@ -0,0 +1,32 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Mem_conn_info extends Db_conn_info__base {
public Mem_conn_info(String raw, String db_api, String database) {super(raw, db_api, database);}
@Override public String Key() {return Tid_const;} public static final String Tid_const = "mem";
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {
return new Mem_conn_info(raw, raw, hash.Get_val_as_str_or_fail("database"));
}
public static Db_conn_info new_(String database) {
return Db_conn_info_.parse(Bld_raw
( "gplx_key", Tid_const
, "database", database
));
}
public static final Mem_conn_info Instance = new Mem_conn_info("", "", "");
}

View File

@@ -0,0 +1,74 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
class Mem_db_fxt {
public Mem_db_fxt() {
Io_mgr.Instance.InitEngine_mem();
Db_conn_bldr.Instance.Reg_default_mem();
}
public Db_conn Make_conn(String url) {return Db_conn_bldr.Instance.Get_or_autocreate(Bool_.Y, Io_url_.mem_fil_(url));}
public Dbmeta_tbl_itm Exec__create_tbl(Db_conn conn, String tbl, String... fld_names) {
Dbmeta_fld_list flds = new Dbmeta_fld_list();
int len = fld_names.length;
for (int i = 0; i < len; ++i)
flds.Add_str(fld_names[i], 255);
Dbmeta_tbl_itm rv = Dbmeta_tbl_itm.New(tbl, flds);
conn.Meta_tbl_create(rv);
return rv;
}
public void Exec__insert(Db_conn conn, String tbl_name, String[]... rows) {
Mem_engine engine = (Mem_engine)conn.Engine();
int rows_len = rows.length;
Mem_tbl tbl = engine.Tbls__get(tbl_name);
Dbmeta_fld_list flds_list = tbl.Meta().Flds().To_fld_list();
int flds_len = flds_list.Len();
Db_stmt stmt = conn.Stmt_insert(tbl_name, flds_list);
for (int i = 0; i < rows_len; ++i) {
stmt.Clear();
String[] row = rows[i];
for (int j = 0; j < flds_len; ++j)
stmt.Val_str(flds_list.Get_at(j).Name(), row[j]);
stmt.Exec_insert();
}
}
public void Test__select(Db_conn conn, Db_qry qry, String[]... expd) {
Db_stmt stmt = conn.Stmt_new(qry);
Db_rdr rdr = new Mem_exec_select((Mem_engine)conn.Engine()).Select((Mem_stmt)stmt);
List_adp actl_list = List_adp_.New();
Bry_bfr tmp_bfr = Bry_bfr_.New();
int expd_len = expd.length;
String[] expd_rows = new String[expd_len];
for (int i = 0; i < expd_len; ++i) {
String[] expd_row = expd[i];
for (int j = 0; j < expd_row.length; ++j) {
if (j != 0) tmp_bfr.Add_byte_pipe();
tmp_bfr.Add_str_u8(expd_row[j]);
}
expd_rows[i] = tmp_bfr.To_str_and_clear();
}
while (rdr.Move_next()) {
int fld_len = rdr.Fld_len();
for (int i = 0; i < fld_len; ++i) {
if (i != 0) tmp_bfr.Add_byte_pipe();
tmp_bfr.Add_obj_strict(rdr.Read_at(i));
}
actl_list.Add(tmp_bfr.To_str_and_clear());
}
Tfds.Eq_ary(expd_rows, (String[])actl_list.To_ary_and_clear(String.class));
}
}

View File

@@ -0,0 +1,72 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
public class Mem_engine implements Db_engine {
private final Hash_adp tbl_hash = Hash_adp_.New();
Mem_engine(Db_conn_info conn_info) {
this.conn_info = conn_info;
this.qry_runner = new Mem_exec_select(this);
}
public String Tid() {return Mem_conn_info.Tid_const;}
public Db_conn_info Conn_info() {return conn_info;} private Db_conn_info conn_info;
public Db_conn_props_mgr Props() {return props;} private final Db_conn_props_mgr props = new Db_conn_props_mgr();
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Mem_exec_select Qry_runner() {return qry_runner;} private Mem_exec_select qry_runner;
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
public Db_engine New_clone(Db_conn_info conn_info) {return new Mem_engine(conn_info);}
public Db_stmt Stmt_by_qry(Db_qry qry) {return new Mem_stmt(this, qry);}
public Mem_tbl Tbls__get(String name) {return (Mem_tbl)tbl_hash.Get_by(name);}
public void Tbls__del(String name) {tbl_hash.Del(name);}
public void Txn_bgn(String name) {}//++txn_count;} private int txn_count = 0;
public String Txn_end() {return "";}// --txn_count; return "";}
public void Txn_cxl() {}//--txn_count;}
public void Txn_sav() {this.Txn_end(); this.Txn_bgn("");}
public Object Exec_as_obj(Db_qry qry) {throw Err_.new_unimplemented();}
public void Conn_open() {}
public void Conn_term() {
// if (txn_count != 0) throw Err_.new_wo_type("Conn_term.txns still open", "txn_count", txn_count); // IGNORE: causing test to fails; DATE:2016-03-30
}
public Db_rdr Exec_as_rdr__rls_manual(Object rdr_obj, String sql) {throw Err_.new_unimplemented();}
public Db_rdr Exec_as_rdr__rls_auto(Db_stmt stmt, Object rdr_obj, String sql) {throw Err_.new_unimplemented();}
public DataRdr New_rdr(java.sql.ResultSet rdr, String sql) {throw Err_.new_unimplemented();}
public Object Stmt_by_sql(String sql) {throw Err_.new_unimplemented();}
public void Meta_tbl_create(Dbmeta_tbl_itm meta) {
Mem_tbl mem_tbl = new Mem_tbl(meta);
tbl_hash.Add_if_dupe_use_nth(meta.Name(), mem_tbl);
meta_mgr.Add(meta);
}
public void Meta_tbl_delete(String tbl_key) {
Mem_tbl tbl = (Mem_tbl)tbl_hash.Get_by(tbl_key);
if (tbl != null) tbl.rows.Clear();
}
public void Meta_idx_create(Gfo_usr_dlg usr_dlg, Dbmeta_idx_itm... ary) {} // TODO_OLD: implement unique index
public void Meta_idx_delete(String idx) {}
public void Meta_fld_append(String tbl, Dbmeta_fld_itm fld) {}
public Dbmeta_tbl_mgr Meta_mgr() {return meta_mgr;} private final Dbmeta_tbl_mgr meta_mgr = new Dbmeta_tbl_mgr(Dbmeta_reload_cmd_.Noop);
public boolean Meta_tbl_exists(String tbl) {return tbl_hash.Has(tbl);}
public boolean Meta_fld_exists(String tbl, String fld) {
Mem_tbl mem_tbl = (Mem_tbl)tbl_hash.Get_by(tbl); if (mem_tbl == null) return false;
return mem_tbl.Meta().Flds().Has(fld);
}
public boolean Meta_idx_exists(String idx) {return false;}
public void Env_db_attach(String alias, Db_conn conn) {}
public void Env_db_attach(String alias, Io_url db_url) {}
public void Env_db_detach(String alias) {}
public static final Mem_engine Instance = new Mem_engine(); Mem_engine() {}
}

View File

@@ -0,0 +1,211 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.criterias.*;
import gplx.dbs.qrys.*; import gplx.dbs.sqls.itms.*;
public class Mem_exec_select {
private final Mem_engine engine;
private final List_adp tmp_where_rows = List_adp_.New();
public Mem_exec_select(Mem_engine engine) {this.engine = engine;}
public Db_rdr Select(Mem_stmt stmt) {
Db_qry stmt_qry = stmt.Qry();
Mem_tbl tbl = engine.Tbls__get(stmt_qry.Base_table());
String[] select = null; Criteria where = null;
Db_qry__select_in_tbl qry = Db_qry__select_in_tbl.as_(stmt_qry);
Db_qry__select_cmd qry2 = null;
if (qry == null) {
qry2 = (Db_qry__select_cmd)stmt_qry;
select = Mem_exec_.Flds__to_str_ary(qry2.Cols().Flds);
where = qry2.Where_itm().Root;
}
else {
select = qry.Select_flds();
where = qry.Where();
}
Mem_stmt_args_.Fill(stmt.Stmt_args(), where);
Mem_row[] tbl_rows = (Mem_row[])tbl.rows.To_ary(Mem_row.class);
if (qry2 != null) {
tbl_rows = Mem_exec_.Rows__alias(tbl_rows, qry2.From().Base_tbl.Alias);
List_adp join_tbls = qry2.From().Tbls;
int join_tbls_len = join_tbls.Len();
for (int i = 1; i < join_tbls_len; ++i) {
Sql_tbl_itm join_tbl = (Sql_tbl_itm)join_tbls.Get_at(i);
Mem_row[] join_rows = (Mem_row[])engine.Tbls__get(join_tbl.Name).rows.To_ary(Mem_row.class);
join_rows = Mem_exec_.Rows__alias(join_rows, join_tbl.Alias);
tbl_rows = Mem_exec_.Rows__join(join_tbl.Join_tid, tbl_rows, join_rows, join_tbl.Alias, join_tbl.Join_flds);
}
}
Mem_exec_.Where__filter(tmp_where_rows, tbl_rows, stmt, where);
Mem_row[] rslt_rows = (Mem_row[])tmp_where_rows.To_ary_and_clear(Mem_row.class);
if (qry2 != null) {
if (qry2.Order() != null && qry2.Order().Flds().length > 0)
Array_.Sort(rslt_rows, new Mem_sorter(qry2.Order().Flds()));
int offset = qry2.Offset();
if (offset != Db_qry__select_cmd.Offset__disabled) {
Mem_row[] trg_rows = new Mem_row[rslt_rows.length - offset];
Array_.Copy_to(rslt_rows, offset, trg_rows, 0, trg_rows.length);
rslt_rows = trg_rows;
}
int limit = qry2.Limit();
if (limit != Db_qry__select_cmd.Limit__disabled) {
Mem_row[] trg_rows = new Mem_row[limit];
Array_.Copy_to(rslt_rows, 0, trg_rows, 0, limit);
rslt_rows = trg_rows;
}
rslt_rows = Mem_exec_.Rows__select_flds(rslt_rows, qry2.Cols());
}
return new Mem_rdr(select, rslt_rows);
}
}
class Mem_sorter implements gplx.core.lists.ComparerAble {
private final Sql_order_fld[] flds;
public Mem_sorter(Sql_order_fld[] flds) {
this.flds = flds;
}
public int compare(Object lhsObj, Object rhsObj) {
Mem_row lhs = (Mem_row)lhsObj;
Mem_row rhs = (Mem_row)rhsObj;
int flds_len = flds.length;
for (int i = 0; i < flds_len; ++i) {
Sql_order_fld fld = flds[i];
Object lhs_val = lhs.Get_by(fld.Name);
Object rhs_val = rhs.Get_by(fld.Name);
int comp = CompareAble_.Compare_obj(lhs_val, rhs_val);
if (comp != CompareAble_.Same) return comp * (fld.Sort == Sql_order_fld.Sort__dsc ? -1 : 1);
}
return CompareAble_.Same;
}
}
class Mem_exec_ {
public static Mem_row[] Rows__join(int join_tid, Mem_row[] lhs_rows, Mem_row[] rhs_rows, String tbl_alias, Sql_join_fld[] join_flds) {
int join_flds_len = join_flds.length;
Bry_bfr bfr = Bry_bfr_.New();
Hash_adp_bry rhs_hash = Hash_adp_bry.cs();
int rhs_rows_len = rhs_rows.length;
for (int i = 0; i < rhs_rows_len; ++i) {
Mem_row rhs_row = rhs_rows[i];
byte[] rhs_key = Rows__bld_key(bfr, Bool_.N, tbl_alias, rhs_row, join_flds, join_flds_len);
List_adp rhs_list = (List_adp)rhs_hash.Get_by_bry(rhs_key);
if (rhs_list == null) {
rhs_list = List_adp_.New();
rhs_hash.Add(rhs_key, rhs_list);
}
rhs_list.Add(rhs_row);
}
List_adp rv = List_adp_.New();
int lhs_len = lhs_rows.length;
for (int i = 0; i < lhs_len; ++i) {
Mem_row lhs_row = lhs_rows[i];
byte[] lhs_key = Rows__bld_key(bfr, Bool_.Y, tbl_alias, lhs_row, join_flds, join_flds_len);
List_adp rhs_list = (List_adp)rhs_hash.Get_by_bry(lhs_key);
if (rhs_list == null) {
switch (join_tid) {
case Sql_tbl_itm.Tid__inner: continue;
case Sql_tbl_itm.Tid__left: break;
default: throw Err_.new_unhandled_default(join_tid);
}
}
int rhs_list_len = rhs_list == null ? 1 : rhs_list.Len();
for (int j = 0; j < rhs_list_len; ++j) {
Mem_row rhs_row = rhs_list == null ? Mem_row.Null_row : (Mem_row)rhs_list.Get_at(j);
Mem_row merged = Rows__merge(lhs_row, rhs_row);
rv.Add(merged);
}
}
return (Mem_row[])rv.To_ary_and_clear(Mem_row.class);
}
public static Mem_row[] Rows__alias(Mem_row[] src_rows, String tbl_alias) {
int src_rows_len = src_rows.length;
Mem_row[] rv = new Mem_row[src_rows_len];
for (int i = 0; i < src_rows_len; ++i) {
Mem_row src_row = src_rows[i];
Mem_row trg_row = new Mem_row(); rv[i] = trg_row;
int src_flds_len = src_row.Len();
for (int j = 0; j < src_flds_len; ++j) {
String fld = src_row.Fld_at(j);
Object val = src_row.Get_at(j);
trg_row.Add(Sql_select_fld.Bld_tbl_w_fld(tbl_alias, fld), val);
}
}
return rv;
}
private static byte[] Rows__bld_key(Bry_bfr bfr, boolean join_is_src, String trg_tbl, Mem_row row, Sql_join_fld[] join_flds, int join_flds_len) {
for (int i = 0; i < join_flds_len; ++i) {
if (i != 0) bfr.Add_byte_pipe();
Sql_join_fld join_fld = join_flds[i];
Object val = row.Get_by(join_fld.To_fld_sql(join_is_src, trg_tbl));
bfr.Add_obj(val);
}
return bfr.To_bry_and_clear();
}
private static Mem_row Rows__merge(Mem_row lhs, Mem_row rhs) {
Mem_row rv = new Mem_row();
Rows__copy_to(lhs, rv);
Rows__copy_to(rhs, rv);
return rv;
}
private static void Rows__copy_to(Mem_row src, Mem_row trg) {
int src_len = src.Len();
for (int i = 0; i < src_len; ++i) {
String fld = src.Fld_at(i);
Object val = src.Get_by_or_dbnull(fld);
trg.Add(fld, val);
}
}
public static Mem_row[] Rows__select_flds(Mem_row[] src_rows, Sql_select_clause cols) {
Sql_select_fld_list select_flds = cols.Flds; int select_flds_len = select_flds.Len();
int src_rows_len = src_rows.length;
Mem_row[] rv = new Mem_row[src_rows_len];
for (int i = 0; i < src_rows_len; ++i) { // loop over each row
Mem_row src_row = src_rows[i];
Mem_row trg_row = new Mem_row(); rv[i] = trg_row;
for (int j = 0; j < select_flds_len; ++j) { // loop over each fld
Sql_select_fld fld = select_flds.Get_at(j);
if (String_.Eq(fld.Alias, Sql_select_fld.Fld__wildcard)) { // wildcard; add all cols
for (int k = 0; k < src_row.Len(); ++k) {
String key = src_row.Fld_at(k);
Object val = src_row.Get_by_or_dbnull(key);
trg_row.Add(key, val);
}
}
else { // regular field; add it only
String key = fld.To_fld_key();
Object val = src_row.Get_by_or_dbnull(key);
trg_row.Add(fld.To_fld_alias(), val);
}
}
}
return rv;
}
public static String[] Flds__to_str_ary(Sql_select_fld_list flds) {
int len = flds.Len();
String[] rv = new String[len];
for (int i = 0; i < len; ++i)
rv[i] = flds.Get_at(i).Fld;
return rv;
}
public static void Where__filter(List_adp rv, Mem_row[] rows, Mem_stmt stmt, Criteria crt) {
rv.Clear();
int rows_len = rows.length;
for (int i = 0; i < rows_len; ++i) {
Mem_row itm = rows[i];
if (crt.Matches(itm))
rv.Add(itm);
}
}
}

View File

@@ -0,0 +1,130 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import org.junit.*; import gplx.dbs.sqls.itms.*;
public class Mem_exec_select_tst {
private final Mem_db_fxt__single fxt = new Mem_db_fxt__single();
@Test public void Basic() {
fxt.Exec__create_tbl("tbl_1", "fld_1");
fxt.Exec__insert("tbl_1"
, String_.Ary("a_1")
, String_.Ary("a_2")
, String_.Ary("a_0")
);
// select all
fxt.Test__select(Db_qry_.select_().From_("tbl_1").Cols_all_()
, String_.Ary("a_1")
, String_.Ary("a_2")
, String_.Ary("a_0")
);
// order by
fxt.Test__select(Db_qry_.select_().From_("tbl_1").Cols_all_().Order_("fld_1", Bool_.N)
, String_.Ary("a_2")
, String_.Ary("a_1")
, String_.Ary("a_0")
);
// offset
fxt.Test__select(Db_qry_.select_().From_("tbl_1").Cols_all_().Offset_(1)
, String_.Ary("a_2")
, String_.Ary("a_0")
);
// limit
fxt.Test__select(Db_qry_.select_().From_("tbl_1").Cols_all_().Limit_(2)
, String_.Ary("a_1")
, String_.Ary("a_2")
);
}
@Test public void Join__single() {
fxt.Exec__create_tbl("tbl_1", "fld_a", "fld_1a");
fxt.Exec__create_tbl("tbl_2", "fld_a", "fld_2a");
fxt.Exec__insert("tbl_1"
, String_.Ary("a_0", "1a_0")
, String_.Ary("a_1", "1a_1")
, String_.Ary("a_2", "1a_2")
);
fxt.Exec__insert("tbl_2"
, String_.Ary("a_0", "2a_0")
, String_.Ary("a_2", "2a_2")
);
// inner join
fxt.Test__select(Db_qry_.select_()
.Cols_w_tbl_("t1", "fld_a", "fld_1a").Cols_w_tbl_("t2", "fld_2a")
.From_("tbl_1", "t1")
. Join_("tbl_2", "t2", Db_qry_.New_join__join("fld_a", "t1", "fld_a"))
, String_.Ary("a_0", "1a_0", "2a_0")
, String_.Ary("a_2", "1a_2", "2a_2")
);
// left join
fxt.Test__select(Db_qry_.select_()
.Cols_w_tbl_("t1", "fld_a", "fld_1a").Cols_w_tbl_("t2", "fld_2a")
.From_("tbl_1", "t1")
. Join_(Sql_tbl_itm.Tid__left, Sql_tbl_itm.Db__null, "tbl_2", "t2", Db_qry_.New_join__join("fld_a", "t1", "fld_a"))
, String_.Ary("a_0", "1a_0", "2a_0")
, String_.Ary("a_1", "1a_1", Db_null.Null_str)
, String_.Ary("a_2", "1a_2", "2a_2")
);
}
@Test public void Join__many() {
fxt.Exec__create_tbl("tbl_1", "fld_a", "fld_1a");
fxt.Exec__create_tbl("tbl_2", "fld_a", "fld_2a");
fxt.Exec__insert("tbl_1"
, String_.Ary("a_0", "1a_0")
, String_.Ary("a_1", "1a_1")
);
fxt.Exec__insert("tbl_2"
, String_.Ary("a_0", "2a_0")
, String_.Ary("a_0", "2a_1")
);
// inner join
fxt.Test__select(Db_qry_.select_()
.Cols_w_tbl_("t1", "fld_a", "fld_1a").Cols_w_tbl_("t2", "fld_2a")
.From_("tbl_1", "t1")
. Join_("tbl_2", "t2", Db_qry_.New_join__join("fld_a", "t1", "fld_a"))
, String_.Ary("a_0", "1a_0", "2a_0")
, String_.Ary("a_0", "1a_0", "2a_1")
);
// left join
fxt.Test__select(Db_qry_.select_()
.Cols_w_tbl_("t1", "fld_a", "fld_1a").Cols_w_tbl_("t2", "fld_2a")
.From_("tbl_1", "t1")
. Join_(Sql_tbl_itm.Tid__left, Sql_tbl_itm.Db__null, "tbl_2", "t2", Db_qry_.New_join__join("fld_a", "t1", "fld_a"))
, String_.Ary("a_0", "1a_0", "2a_0")
, String_.Ary("a_0", "1a_0", "2a_1")
, String_.Ary("a_1", "1a_1", Db_null.Null_str)
);
}
}
class Mem_db_fxt__single {
private final Mem_db_fxt mem_fxt;
private final Db_conn conn;
public Mem_db_fxt__single() {
this.mem_fxt = new Mem_db_fxt();
this.conn = mem_fxt.Make_conn("mem/test.db");
}
public void Exec__create_tbl (String tbl, String... fld_names) {mem_fxt.Exec__create_tbl(conn, tbl, fld_names);}
public void Exec__insert (String tbl, String[]... rows) {mem_fxt.Exec__insert(conn, tbl, rows);}
public void Test__select (Db_qry qry, String[]... expd) {mem_fxt.Test__select(conn, qry, expd);}
}

View File

@@ -0,0 +1,24 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Mem_qry_set {
private final List_adp rows = List_adp_.New();
public int Len() {return rows.Count();}
public Mem_row Get_at(int i) {return (Mem_row)rows.Get_at(i);}
public void Add(Mem_row row) {rows.Add(row);}
}

View File

@@ -0,0 +1,46 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Mem_rdr implements Db_rdr {
private final Mem_row[] rows; private int row_idx = -1; private final int rows_len;
private Mem_row row;
public Mem_rdr(String[] cols, Mem_row[] rows) {
this.rows = rows; this.rows_len = rows.length;
}
public boolean Move_next() {
boolean rv = ++row_idx < rows_len;
if (rv)
row = rows[row_idx];
return rv;
}
public byte[] Read_bry(String k) {return (byte[])row.Get_by(k);}
public String Read_str(String k) {return (String)row.Get_by(k);}
public byte[] Read_bry_by_str(String k) {return Bry_.new_u8_safe((String)row.Get_by(k));} // NOTE: null b/c db can have NULL
@gplx.Virtual public void Save_bry_in_parts(Io_url url, String tbl, String fld, String crt_key, Object crt_val) {throw Err_.new_unimplemented();}
public DateAdp Read_date_by_str(String k) {return DateAdp_.parse_iso8561((String)row.Get_by(k));}
public byte Read_byte(String k) {return Byte_.cast(row.Get_by(k));}
public int Read_int(String k) {return Int_.cast(row.Get_by(k));}
public long Read_long(String k) {return Long_.cast(row.Get_by(k));}
public float Read_float(String k) {return Float_.cast(row.Get_by(k));}
public double Read_double(String k) {return Double_.cast(row.Get_by(k));}
public boolean Read_bool_by_byte(String k) {return Byte_.cast(row.Get_by(k)) == 1;}
public int Fld_len() {return row.Len();}
public Object Read_obj(String k) {return row.Get_by(k);}
public Object Read_at(int i) {return row.Get_at(i);}
public void Rls() {}
}

View File

@@ -0,0 +1,39 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Mem_row implements Gfo_invk {
private final Ordered_hash hash = Ordered_hash_.New();
private final Ordered_hash flds = Ordered_hash_.New();
public int Len() {return hash.Len();}
public String Fld_at(int i) {return (String)flds.Get_at(i);}
public Object Get_at(int i) {return hash.Get_at(i);}
public Object Get_by(String key) {return hash.Get_by(key);}
public Object Get_by_or_dbnull(String key) {
Object rv = hash.Get_by(key);
return rv == null ? Db_null.Instance : rv;
}
public void Set_by(String key, Object val) {hash.Add_if_dupe_use_nth(key, val); flds.Add_if_dupe_use_1st(key, key);}
public void Add(String key, Object val) {hash.Add(key, val); flds.Add_if_dupe_use_1st(key, key);}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
Object rv = Get_by(k);
if (rv == null) return Gfo_invk_.Rv_unhandled;
return rv;
}
public static final Mem_row[] Ary_empty = new Mem_row[0];
public static final Mem_row Null_row = new Mem_row();
}

View File

@@ -0,0 +1,148 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*;
public class Mem_stmt implements Db_stmt {
private static final String Key_na = ""; // key is not_available; only called by procs with signature of Val(<type> v);
private final Ordered_hash val_list = Ordered_hash_.New();
public Mem_stmt(Mem_engine engine, Db_qry qry) {Ctor_stmt(engine, qry);} private Mem_engine engine;
public void Ctor_stmt(Db_engine engine, Db_qry qry) {this.engine = (Mem_engine)engine; this.qry = qry;}
public Mem_stmt_args Stmt_args() {return stmt_args;} private final Mem_stmt_args stmt_args = new Mem_stmt_args();
public int Args_len() {return val_list.Count();}
public Object Args_get_at(int i) {return val_list.Get_at(i);}
public Object Args_get_by(String k) {return val_list.Get_by(k);}
public Db_qry Qry() {return qry;} private Db_qry qry;
public Db_stmt Reset_stmt() {return this;}
public Db_stmt Clear() {
val_list.Clear();
stmt_args.Clear();
return this;
}
public void Rls() {this.Clear();}
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, where, 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, where, 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, where, 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, where, 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, where, 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, where, v);} 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) {
try {Add(k, where, 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, where, 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, where, v);} 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, where, 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.streams.Io_stream_rdr v, long rdr_len) {
try {
Bry_bfr bfr = Bry_bfr_.New();
gplx.core.ios.streams.Io_stream_rdr_.Load_all_to_bfr(bfr, v);
Add("", Bool_.N, bfr.To_str_and_clear());
} catch (Exception e) {throw Err_.new_exc(e, "db", "failed to add value", "type", "rdr", "val", v);}
return this;
}
public boolean Exec_insert() {
Mem_tbl tbl = engine.Tbls__get(qry.Base_table());
if (tbl == null) throw Err_.new_wo_type("must call Create_tbl", "tbl", qry.Base_table());
return tbl.Insert(this) == 1;
}
public int Exec_update() {
Mem_tbl tbl = engine.Tbls__get(qry.Base_table());
return tbl.Update(this);
}
public int Exec_delete() {
Mem_tbl tbl = engine.Tbls__get(qry.Base_table());
return tbl.Delete(this);
}
public DataRdr Exec_select() {throw Err_.new_unimplemented();}
public Db_rdr Exec_select__rls_auto() {return this.Exec_select__rls_manual();}
public Db_rdr Exec_select__rls_manual() {
// Mem_tbl tbl = engine.Tbls_get(qry.Base_table());
// return tbl.Select(this);
return engine.Qry_runner().Select(this);
}
public Object Exec_select_val() {throw Err_.new_unimplemented();}
private void Add(String k, boolean where, Object v) {
if (k == Dbmeta_fld_itm.Key_null) return; // key is explicitly null; ignore; allows schema_2+ type definitions
val_list.Add_if_dupe_use_1st(k, v); // NOTE: only add if new; WHERE with IN will call Add many times; fld_ttl IN ('A.png', 'B.png');
if (where) stmt_args.Add(k, v);
}
}

View File

@@ -0,0 +1,77 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.criterias.*;
public class Mem_stmt_args {
private final List_adp list = List_adp_.New();
private int cur_idx = -1;
public void Clear() {list.Clear(); cur_idx = -1;}
public void Add(String k, Object v) {list.Add(Keyval_.new_(k, v));}
public Keyval Get_next() {
int idx = ++cur_idx;
return idx == list.Count() ? null: (Keyval)list.Get_at(idx);
}
}
class Mem_stmt_args_ {
public static void Fill(Mem_stmt_args args, Criteria crt) {
int tid = crt.Tid();
if (tid == Criteria_.Tid_wrapper) {
Criteria_fld fld = (Criteria_fld)crt;
Criteria sub = fld.Crt();
String fld_key = fld.Key();
switch (sub.Tid()) {
case Criteria_.Tid_eq:
case Criteria_.Tid_comp:
case Criteria_.Tid_like:
case Criteria_.Tid_iomatch:
Keyval kvp = args.Get_next();
if (!String_.Eq(kvp.Key(), fld.Key())) throw Err_.new_("db", "fld_crt.key mismatch", "fld.key", fld_key, "kvp.key", kvp.Key());
sub.Val_as_obj_(kvp.Val());
break;
case Criteria_.Tid_in:
Criteria_in crt_in = (Criteria_in)sub;
Object[] ary = crt_in.Ary(); int ary_len = crt_in.Ary_len();
for (int i = 0; i < ary_len; ++i)
ary[i] = args.Get_next().Val();
break;
case Criteria_.Tid_between:
Criteria_between crt_between = (Criteria_between)sub;
crt_between.Lo_((Comparable)(args.Get_next()).Val());
crt_between.Hi_((Comparable)(args.Get_next()).Val());
break;
default: throw Err_.new_unhandled(sub.Tid());
}
}
else {
switch (tid) {
case Criteria_.Tid_const: break; // true / false; nothing to fill
case Criteria_.Tid_and:
case Criteria_.Tid_or:
Criteria_bool_base crt_dual = (Criteria_bool_base)crt;
Fill(args, crt_dual.Lhs());
Fill(args, crt_dual.Rhs());
break;
case Criteria_.Tid_not:
Criteria_not crt_not = (Criteria_not)crt;
Fill(args, crt_not.Crt());
break;
default: throw Err_.new_unhandled(tid);
}
}
}
}

View File

@@ -0,0 +1,106 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mems; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.primitives.*; import gplx.core.criterias.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.itms.*;
import gplx.dbs.metas.*;
public class Mem_tbl {
private final List_adp where_rows = List_adp_.New();
private final Hash_adp autonum_hash = Hash_adp_.New();
public Mem_tbl(Dbmeta_tbl_itm meta) {this.meta = meta;}
public Dbmeta_tbl_itm Meta() {return meta;} private final Dbmeta_tbl_itm meta;
public final List_adp rows = List_adp_.New();
public int Insert(Mem_stmt stmt) {
Mem_row itm = new Mem_row();
Dbmeta_fld_mgr flds = meta.Flds();
int len = flds.Len();
for (int i = 0; i < len; ++i) {
Dbmeta_fld_itm fld = flds.Get_at(i);
String fld_name = fld.Name();
Object val = fld.Autonum() ? Autonum_calc(fld_name) : stmt.Args_get_by(fld_name);
if (val == null) continue; // NOTE: allow Bulk_insert from test to skip filds
itm.Set_by(fld_name, val);
}
rows.Add(itm);
return 1;
}
private int Autonum_calc(String name) {
Int_obj_ref autonum_itm = (Int_obj_ref)autonum_hash.Get_by(name);
if (autonum_itm == null) {
autonum_itm = Int_obj_ref.New(0);
autonum_hash.Add(name, autonum_itm);
}
return autonum_itm.Val_add();
}
public int Update(Mem_stmt stmt) {
Db_qry_update qry = (Db_qry_update)stmt.Qry();
Criteria where_crt = qry.Where(); if (where_crt == null) where_crt = Criteria_.All;
Mem_stmt_args_.Fill(stmt.Stmt_args(), where_crt);
Select_rows_where(where_rows, stmt, where_crt);
int where_rows_len = where_rows.Count();
String[] update_cols = qry.Cols_for_update(); int update_cols_len = update_cols.length;
for (int i = 0; i < where_rows_len; ++i) {
Mem_row itm = (Mem_row)where_rows.Get_at(i);
for (int j = 0; j < update_cols_len; ++j)
itm.Set_by(update_cols[j], stmt.Args_get_at(j));
}
return where_rows_len;
}
public int Delete(Mem_stmt stmt) {
Db_qry_delete qry = (Db_qry_delete)stmt.Qry();
Mem_stmt_args_.Fill(stmt.Stmt_args(), qry.Where());
Select_rows_where(where_rows, stmt, qry.Where());
int where_rows_len = where_rows.Count();
for (int i = 0; i < where_rows_len; ++i) {
Mem_row itm = (Mem_row)where_rows.Get_at(i);
rows.Del(itm);
}
return where_rows_len;
}
public Db_rdr Select(Mem_stmt stmt) {
String[] select = null; Criteria where = null;
Db_qry__select_in_tbl qry = Db_qry__select_in_tbl.as_(stmt.Qry());
if (qry == null) {
Db_qry__select_cmd qry2 = (Db_qry__select_cmd)stmt.Qry();
select = To_str_ary(qry2.Cols().Flds);
where = qry2.Where_itm().Root;
}
else {
select = qry.Select_flds();
where = qry.Where();
}
Mem_stmt_args_.Fill(stmt.Stmt_args(), where);
Select_rows_where(where_rows, stmt, where);
return new Mem_rdr(select, (Mem_row[])where_rows.To_ary_and_clear(Mem_row.class));
}
private String[] To_str_ary(Sql_select_fld_list flds) {
int len = flds.Len();
String[] rv = new String[len];
for (int i = 0; i < len; ++i)
rv[i] = flds.Get_at(i).Fld;
return rv;
}
private void Select_rows_where(List_adp rv, Mem_stmt stmt, Criteria crt) {
rv.Clear();
int rows_len = rows.Count();
for (int i = 0; i < rows_len; ++i) {
Mem_row itm = (Mem_row)rows.Get_at(i);
if (crt.Matches(itm))
rv.Add(itm);
}
}
}

View File

@@ -0,0 +1,45 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mysql; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Mysql_conn_info extends Db_conn_info__base {
public Mysql_conn_info(String raw, String db_api, String database, String server, String uid, String pwd) {super(raw, db_api, database);
this.server = server;
this.uid = uid;
this.pwd = pwd;
}
@Override public String Key() {return Tid_const;} public static final String Tid_const = "mysql";
public String Server() {return server;} private final String server;
public String Uid() {return uid;} private final String uid;
public String Pwd() {return pwd;} private final String pwd;
public static Db_conn_info new_(String server, String database, String uid, String pwd) {
return Db_conn_info_.parse(Bld_raw
( "gplx_key", Tid_const
, "server", server
, "database", database
, "uid", uid
, "pwd", pwd
, "charset", "utf8"
));
}
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {
return new Mysql_conn_info
( raw, Bld_api(hash, Keyval_.new_("charset", "utf8")), hash.Get_val_as_str_or_fail("database")
, hash.Get_val_as_str_or_fail("server"), hash.Get_val_as_str_or_fail("uid"), hash.Get_val_as_str_or_fail("pwd"));
}
public static final Mysql_conn_info Instance = new Mysql_conn_info("", "", "", "", "", "");
}

View File

@@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.mysql; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.sqls.*; import gplx.dbs.metas.*;
import java.sql.*;
public class Mysql_engine extends Db_engine_sql_base {
@Override public String Tid() {return Mysql_conn_info.Tid_const;}
@Override public Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__mysql();}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Mysql_engine rv = new Mysql_engine();
rv.Ctor(connectInfo);
return rv;
}
@Override public DataRdr New_rdr(ResultSet rdr, String commandText) {return Mysql_rdr.new_(rdr, commandText);}
@Override public Dbmeta_tbl_mgr Meta_mgr() {throw Err_.new_unimplemented();}
@gplx.Internal @Override protected Connection Conn_make() {
Mysql_conn_info conn_info_as_mysql = (Mysql_conn_info)conn_info;
Connection rv = Conn_make_by_url("jdbc:mysql://localhost/" + conn_info_as_mysql.Database() + "?characterEncoding=UTF8&useSSL=false", conn_info_as_mysql.Uid(), conn_info_as_mysql.Pwd());
return rv;
}
public static final Mysql_engine Instance = new Mysql_engine(); Mysql_engine() {}
}
class Mysql_rdr extends Db_data_rdr {
//PATCH:MYSQL:byte actually returned as int by Jdbc ResultSet (or MYSQL impmentation); convert to byte
@Override public byte ReadByte(String key) {return ReadByteOr(key, Byte.MAX_VALUE);}
@Override public byte ReadByteOr(String key, byte or) {
Object val = Read(key);
return val == null ? or : ((Integer)val).byteValue();
}
public static Mysql_rdr new_(ResultSet rdr, String commandText) {
Mysql_rdr rv = new Mysql_rdr();
rv.ctor_db_data_rdr(rdr, commandText);
return rv;
} Mysql_rdr() {}
}

View File

@@ -0,0 +1,24 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.noops; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Noop_conn_info extends Db_conn_info__base {
public Noop_conn_info(String raw, String db_api, String database) {super(raw, db_api, database);}
@Override public String Key() {return Tid_const;} public static final String Tid_const = "null_db";
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {return this;}
public static final Noop_conn_info Instance = new Noop_conn_info("gplx_key=null_db", "", "");
}

View File

@@ -0,0 +1,52 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.noops; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.bats.*;
public class Noop_engine implements Db_engine {
public String Tid() {return Noop_conn_info.Tid_const;}
public Db_conn_info Conn_info() {return Db_conn_info_.Null;}
public Db_conn_props_mgr Props() {return props;} private final Db_conn_props_mgr props = new Db_conn_props_mgr();
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
public void Conn_open() {}
public void Conn_term() {}
public Db_engine New_clone(Db_conn_info url) {return this;}
public Db_rdr Exec_as_rdr__rls_manual (Object rdr_obj, String sql) {return Db_rdr_.Empty;}
public Db_rdr Exec_as_rdr__rls_auto (Db_stmt stmt, Object rdr_obj, String sql) {return Db_rdr_.Empty;}
public Db_stmt Stmt_by_qry(Db_qry qry) {return Db_stmt_.Null;}
public Object Stmt_by_sql(String sql) {throw Err_.new_unimplemented();}
public DataRdr New_rdr(java.sql.ResultSet rdr, String sql) {return DataRdr_.Null;}
public void Txn_bgn(String name) {}
public String Txn_end() {return "";}
public void Txn_cxl() {}
public void Txn_sav() {}
public Object Exec_as_obj(Db_qry cmd) {return cmd.Exec_is_rdr() ? (Object)DataRdr_.Null : -1;}
public void Meta_tbl_create(Dbmeta_tbl_itm meta) {}
public void Meta_tbl_delete(String tbl) {}
public void Meta_idx_create(Gfo_usr_dlg usr_dlg, Dbmeta_idx_itm... ary) {}
public void Meta_idx_delete(String idx) {}
public void Meta_fld_append(String tbl, Dbmeta_fld_itm fld) {}
public void Env_db_attach(String alias, Db_conn conn) {}
public void Env_db_attach(String alias, Io_url db_url) {}
public void Env_db_detach(String alias) {}
public boolean Meta_tbl_exists(String tbl) {return false;}
public boolean Meta_fld_exists(String tbl, String fld) {return false;}
public boolean Meta_idx_exists(String idx) {return false;}
public Dbmeta_tbl_mgr Meta_mgr() {return meta_tbl_mgr;} private final Dbmeta_tbl_mgr meta_tbl_mgr = new Dbmeta_tbl_mgr(Dbmeta_reload_cmd_.Noop);
public static final Noop_engine Instance = new Noop_engine(); Noop_engine() {}
}

View File

@@ -0,0 +1,46 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.postgres; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Postgres_conn_info extends Db_conn_info__base {
public Postgres_conn_info(String raw, String db_api, String database, String server, String uid, String pwd) {super(raw, db_api, database);
this.server = server;
this.uid = uid;
this.pwd = pwd;
}
@Override public String Key() {return Tid_const;} public static final String Tid_const = "postgresql";
public String Server() {return server;} private final String server;
public String Uid() {return uid;} private final String uid;
public String Pwd() {return pwd;} private final String pwd;
public static Db_conn_info new_(String server, String database, String uid, String pwd) {
return Db_conn_info_.parse(Bld_raw
( "gplx_key", Tid_const
, "server", server
, "database", database
, "port", "5432"
, "user id", uid
, "password", pwd
, "encoding", "unicode" // needed for 1.1 conn; otherwise, ascii
));
}
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {
return new Postgres_conn_info
( raw, Bld_api(hash, Keyval_.new_("encoding", "unicode")), hash.Get_val_as_str_or_fail("database")
, hash.Get_val_as_str_or_fail("server"), hash.Get_val_as_str_or_fail("user id"), hash.Get_val_as_str_or_fail("password"));
}
public static final Postgres_conn_info Instance = new Postgres_conn_info("", "", "", "", "", "");
}

View File

@@ -0,0 +1,36 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.postgres; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.sqls.*; import gplx.dbs.metas.*;
import java.sql.*;
public class Postgres_engine extends Db_engine_sql_base {
@Override public String Tid() {return Postgres_conn_info.Tid_const;}
@Override public Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__mysql();}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Postgres_engine rv = new Postgres_engine();
rv.Ctor(connectInfo);
return rv;
}
@Override public DataRdr New_rdr(ResultSet rdr, String commandText) {return Db_data_rdr_.new_(rdr, commandText);}
@Override public Dbmeta_tbl_mgr Meta_mgr() {throw Err_.new_unimplemented();}
@gplx.Internal @Override protected Connection Conn_make() {
Postgres_conn_info conn_info_as_postgres = (Postgres_conn_info)conn_info;
return Conn_make_by_url("jdbc:" + conn_info_as_postgres.Key() + "://localhost/" + conn_info_as_postgres.Database(), conn_info_as_postgres.Uid(), conn_info_as_postgres.Pwd());
}
public static final Postgres_engine Instance = new Postgres_engine(); Postgres_engine() {}
}

View File

@@ -0,0 +1,49 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Sqlite_conn_info extends Db_conn_info__base {
public Sqlite_conn_info(String raw, String db_api, String database, Io_url url) {super(raw, db_api, database);this.url = url;}
@Override public String Key() {return Key_const;} public static final String Key_const = "sqlite";
public Io_url Url() {return url;} private final Io_url url;
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {
Io_url url = Io_url_.new_any_(hash.Get_val_as_str_or_fail("data source"));
String db = url.NameOnly();
String api = Bld_api(hash, Keyval_.new_("version", "3"));
return new Sqlite_conn_info(raw, api, db, url);
}
public static final Sqlite_conn_info Instance = new Sqlite_conn_info("", "", "", Io_url_.Empty);
public static Db_conn_info load_(Io_url url) {
return Db_conn_info_.parse(Bld_raw
( "gplx_key" , Key_const
, Cs__data_source , url.Xto_api()
, Cs__version , Cs__version__3
));
}
public static Db_conn_info make_(Io_url url) {
Io_mgr.Instance.CreateDirIfAbsent(url.OwnerDir());
return Db_conn_info_.parse(Bld_raw
( "gplx_key" , Key_const
, Cs__data_source , url.Xto_api()
, Cs__version , Cs__version__3
));
}
public static final String Cs__data_source = "data source", Cs__version = "version", Cs__version__3 = "3";
public static Io_url To_url(Db_conn conn) {return ((Sqlite_conn_info)conn.Conn_info()).url;}
}

View File

@@ -0,0 +1,165 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import java.sql.*;
import gplx.core.stores.*; import gplx.dbs.engines.*; import gplx.dbs.engines.sqlite.*; import gplx.dbs.metas.*; import gplx.dbs.sqls.*;
import gplx.dbs.qrys.*;
import gplx.core.ios.IoItmFil;
import org.sqlite.SQLiteConnection;
public class Sqlite_engine extends Db_engine_sql_base {
private final Sqlite_txn_mgr txn_mgr; private final Sqlite_schema_mgr schema_mgr;
Sqlite_engine() {
this.txn_mgr = new Sqlite_txn_mgr(this);
this.schema_mgr = new Sqlite_schema_mgr(this);
}
@Override public String Tid() {return Sqlite_conn_info.Key_const;}
@Override public gplx.dbs.sqls.Sql_qry_wtr Sql_wtr() {return Sql_qry_wtr_.New__sqlite();}
@Override public Db_engine New_clone(Db_conn_info connectInfo) {
Sqlite_engine rv = new Sqlite_engine();
rv.Ctor(connectInfo);
return rv;
}
@Override public DataRdr New_rdr(ResultSet rdr, String commandText) {return Sqlite_rdr.new_(rdr, commandText);}
@Override public Db_rdr New_rdr_clone() {return new Db_rdr__sqlite();}
@Override public void Env_db_attach(String alias, Db_conn conn) {
Db_conn_info cs_obj = conn.Conn_info(); if (!String_.Eq(cs_obj.Key(), Sqlite_conn_info.Key_const)) throw Err_.new_("dbs", "must attach to sqlite databases", "conn", cs_obj.Raw());
Sqlite_conn_info cs = (Sqlite_conn_info)cs_obj;
Env_db_attach(alias, cs.Url());
}
@Override public void Env_db_attach(String alias, Io_url db_url) {Exec_as_int(String_.Format("ATTACH '{0}' AS {1};", db_url.Raw(), alias));}
@Override public void Env_db_detach(String alias) {Exec_as_int(String_.Format("DETACH {0};", alias));}
@Override public void Txn_bgn(String name) {txn_mgr.Txn_bgn(name);}
@Override public String Txn_end() {return txn_mgr.Txn_end();}
@Override public void Txn_cxl() {txn_mgr.Txn_cxl();}
@Override public void Txn_sav() {txn_mgr.Txn_sav();}
@Override public Dbmeta_tbl_mgr Meta_mgr() {return schema_mgr.Tbl_mgr();}
@Override public boolean Meta_tbl_exists(String tbl) {return schema_mgr.Tbl_exists(tbl);}
@Override public boolean Meta_fld_exists(String tbl, String fld) {return schema_mgr.Fld_exists(tbl, fld);}
@Override public boolean Meta_idx_exists(String idx) {return schema_mgr.Idx_exists(idx);}
@Override public Db_stmt Stmt_by_qry(Db_qry qry) {return new Sqlite_stmt(this, qry);}
private static boolean loaded = false;
protected void Meta_tbl_gather_hook() {throw Err_.new_unimplemented();}
@gplx.Internal @Override protected Connection Conn_make() {
if (!loaded) {
try {
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {throw Err_.new_exc(e, "db", "could not load sqlite jdbc driver");}
loaded = true;
}
// init vars for opening connection
Sqlite_conn_info conn_info_as_sqlite = (Sqlite_conn_info)conn_info;
Io_url sqlite_fs_url = conn_info_as_sqlite.Url();
String sqlite_db_url = "jdbc:sqlite://" + String_.Replace(sqlite_fs_url.Raw(), "\\", "/");
// set open_mode flag if conn is read-only; needed else all SELECT queries will be very slow; DATE:2016-09-03
IoItmFil sqlite_fs_itm = Io_mgr.Instance.QueryFil(sqlite_fs_url);
Keyval[] props = sqlite_fs_itm.Exists() && sqlite_fs_itm.ReadOnly() // NOTE: must check if it exists; else missing-file will be marked as readonly connection, and missing-file will sometimes be dynamically created as read-write; DATE:2016-09-04
? Keyval_.Ary(Keyval_.new_("open_mode", "1"))
: Keyval_.Ary_empty;
// open connection
Connection rv = Conn__new_by_url_and_props(sqlite_db_url, props);
// set busyTimeout; needed else multiple processes accessing same db can cause "database is locked" error; DATE:2016-09-03
SQLiteConnection rv_as_sqlite = (org.sqlite.SQLiteConnection)rv;
try {rv_as_sqlite.setBusyTimeout(10000);}
catch (SQLException e) {Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to set busy timeout; err=~{0}", Err_.Message_gplx_log(e));}
return rv;
}
public static final Sqlite_engine Instance = new Sqlite_engine();
}
class Db_rdr__sqlite extends Db_rdr__basic { @Override public byte Read_byte(String k) {try {return (byte)Int_.cast(rdr.getObject(k));} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed", "k", k, "type", Byte_.Cls_val_name);}}
@Override public boolean Read_bool_by_byte(String k) {
try {
int val = rdr.getInt(k);
return val == 1;
} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed", "i", k, "type", Bool_.Cls_val_name);}
}
@Override public long Read_long(String k) {
try {
long val = rdr.getLong(k);
Number n = (Number)val;
return n.longValue();
} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed", "i", k, "type", Long_.Cls_val_name);}
}
@Override public float Read_float(String k) {
try {
Double val = (Double)rdr.getDouble(k);
return val == null ? Float.NaN : val.floatValue();
} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed:", "i", k, "type", Float_.Cls_val_name);}
}
@Override public DateAdp Read_date_by_str(String k) {
try {
String val = rdr.getString(k);
return val == null ? null : DateAdp_.parse_fmt(val, "yyyyMMdd_HHmmss");
} catch (Exception e) {throw Err_.new_exc(e, "db", "read failed", "i", k, "type", DateAdp_.Cls_ref_type);}
}
// @Override public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) {
// Object val = Read(key);
// Double d = ((Double)val);
// return val == null ? null : DecimalAdp_.double_(d);
// }
}
class Sqlite_rdr extends Db_data_rdr { @Override public float ReadFloat(String key) {return ReadFloatOr(key, Float.NaN);}
@Override public float ReadFloatOr(String key, float or) {
Object val = Read(key);
Double d = ((Double)val);
return val == null ? or : d.floatValue();
}
@Override public Decimal_adp ReadDecimal(String key) {return ReadDecimalOr(key, null);}
@Override public Decimal_adp ReadDecimalOr(String key, Decimal_adp or) {
Object val = Read(key);
Double d = ((Double)val);
return val == null ? or : Decimal_adp_.double_(d);
}
@Override public DateAdp ReadDate(String key) {return ReadDateOr(key, null);}
@Override public DateAdp ReadDateOr(String key, DateAdp or) {
Object val = Read(key);
return val == null ? or : DateAdp_.parse_fmt((String)val, "M/dd/yyyy hh:mm tt");
}
@Override public boolean ReadBool(String key) {return ReadBoolOr(key, false);}
@Override public boolean ReadBoolOr(String key, boolean or) {
Object val = Read(key);
return val == null ? or : Int_.cast(val) == 1;
}
@Override public byte ReadByte(String key) {return ReadByteOr(key, Byte_.Zero);}
@Override public byte ReadByteOr(String key, byte or) {
Object val = Read(key);
return val == null ? or : (byte)Int_.cast(val);
}
@Override public long ReadLong(String key) {return ReadLongOr(key, Long_.Min_value);}
@Override public long ReadLongOr(String key, long or) {
Object val = Read(key);
if (val == null) return or;
Number n = (Number)val;
return n.longValue();
}
public static Sqlite_rdr new_(ResultSet rdr, String commandText) {
Sqlite_rdr rv = new Sqlite_rdr();
rv.ctor_db_data_rdr(rdr, commandText);
return rv;
} Sqlite_rdr() {}
}
class Sqlite_stmt extends gplx.dbs.qrys.Db_stmt_cmd { public Sqlite_stmt(Db_engine engine, Db_qry qry) {super(engine, qry);}
@Override protected Db_stmt Add_date(boolean where, String k, DateAdp v) {
if (k == Dbmeta_fld_itm.Key_null) return this; // key is explicitly null; ignore; allows version_2+ type definitions
return super.Add_str(where, k, v.XtoStr_fmt_iso_8561());
}
}

View File

@@ -0,0 +1,79 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.primitives.*; import gplx.dbs.qrys.*; import gplx.dbs.utls.*; import gplx.dbs.engines.*; import gplx.dbs.engines.sqlite.*;
public class Sqlite_engine_ {
public static void Db_attach(Db_conn p, String alias, String url) {
String s = String_.Format("ATTACH '{0}' AS {1};", url, alias);
Db_qry qry = Db_qry_sql.xtn_(s);
p.Exec_qry(qry);
}
public static void Db_detach(Db_conn p, String alias) {
String s = String_.Format("DETACH '{0}';", alias);
Db_qry qry = Db_qry_sql.xtn_(s);
p.Exec_qry(qry);
}
public static void Tbl_create_and_delete(Db_conn p, String tbl_name, String tbl_sql) {
Tbl_delete(p, tbl_name);
Db_qry qry = Db_qry_sql.ddl_(tbl_sql);
p.Exec_qry(qry);
}
public static void Tbl_create(Db_conn p, String tbl_name, String tbl_sql) {
Db_qry qry = Db_qry_sql.ddl_(tbl_sql);
p.Exec_qry(qry);
}
public static void Tbl_delete_many(Db_conn p, String... tbls) {
int len = tbls.length;
for (int i = 0; i < len; i++)
Tbl_delete(p, tbls[i]);
}
public static void Tbl_delete(Db_conn p, String tbl) {
Db_qry qry = Db_qry_sql.ddl_("DROP TABLE IF EXISTS " + tbl + ";");
p.Exec_qry(qry);
}
public static void Tbl_rename(Db_conn p, String src, String trg) {
Db_qry qry = Db_qry_sql.ddl_(String_.Format("ALTER TABLE {0} RENAME TO {1};", src, trg));
p.Exec_qry(qry);
}
public static void Idx_create(Gfo_usr_dlg usr_dlg, Db_conn conn, String tbl, Dbmeta_idx_itm[] idx_ary) {
int len = idx_ary.length;
for (int i = 0; i < len; ++i) {
Dbmeta_idx_itm idx = idx_ary[i];
String idx_sql = idx.To_sql_create(conn.Engine().Sql_wtr());
usr_dlg.Plog_many("", "", "creating index: ~{0} ~{1}", tbl, idx_sql);
conn.Exec_qry(Db_qry_sql.ddl_(idx.To_sql_create(conn.Engine().Sql_wtr())));
usr_dlg.Log_many("", "", "index created: ~{0} ~{1}", tbl, idx_sql);
}
}
public static void Idx_create(Db_conn p, Db_idx_itm... idxs) {Idx_create(Gfo_usr_dlg_.Noop, p, "", idxs);}
public static void Idx_create(Gfo_usr_dlg usr_dlg, Db_conn p, String file_id, Db_idx_itm... idxs) {
int len = idxs.length;
for (int i = 0; i < len; i++) {
String index = idxs[i].Xto_sql();
usr_dlg.Plog_many("", "", "creating index: ~{0} ~{1}", file_id, index);
p.Exec_qry(Db_qry_sql.ddl_(index));
usr_dlg.Log_many("", "", "index created: ~{0} ~{1}", file_id, index);
}
}
public static final int Stmt_arg_max = 999; // 999 is max number of variables allowed by sqlite
public static final boolean Supports_read_binary_stream = false;
public static final boolean Supports_indexed_by = true;
public static String X_date_to_str(DateAdp v) {return v == Date_null ? "" : v.XtoStr_fmt_iso_8561();}
public static final DateAdp Date_null = null;
public static final byte Wildcard_byte = Byte_ascii.Hash;
}

View File

@@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.primitives.*; import gplx.dbs.qrys.*; import gplx.dbs.utls.*; import gplx.dbs.engines.*; import gplx.dbs.engines.sqlite.*;
public class Sqlite_pragma implements Db_qry {
private final String sql;
public Sqlite_pragma(boolean parens, String key, String val) {
String fmt = parens ? "PRAGMA {0}({1});" : "PRAGMA {0} = {1};";
this.sql = String_.Format(fmt, key, val);
}
public int Tid() {return Db_qry_.Tid_pragma;}
public boolean Exec_is_rdr() {return false;}
public String Base_table() {return "";}
public String To_sql__exec(gplx.dbs.sqls.Sql_qry_wtr wtr) {return sql;}
public static final String Const__journal_mode = "journal_mode", Const__journal_mode__wal = "wal", Const__journal_mode__off = "off";
public static Sqlite_pragma New__journal__delete() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , "delete");} // default
public static Sqlite_pragma New__journal__truncate() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , "truncate");}
public static Sqlite_pragma New__journal__persist() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , "persist");}
public static Sqlite_pragma New__journal__memory() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , "memory");}
public static Sqlite_pragma New__journal__wal() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , Const__journal_mode__wal);}
public static Sqlite_pragma New__journal__off() {return new Sqlite_pragma(Bool_.N, Const__journal_mode , Const__journal_mode__off);}
public static Sqlite_pragma New__synchronous__off() {return new Sqlite_pragma(Bool_.N, "synchronous" , "off");}
public static Sqlite_pragma New__synchronous__normal() {return new Sqlite_pragma(Bool_.N, "synchronous" , "normal");} // default if WAL
public static Sqlite_pragma New__synchronous__full() {return new Sqlite_pragma(Bool_.N, "synchronous" , "full");} // default otherwise
public static Sqlite_pragma New__synchronous__extra() {return new Sqlite_pragma(Bool_.N, "synchronous" , "extra");}
public static Sqlite_pragma New__wal_autocheckpoint(int v) {return new Sqlite_pragma(Bool_.N, "wal_auto_checkpoint", Int_.To_str(v));} // default is 1000
public static Sqlite_pragma New__wal_checkpoint__passive() {return new Sqlite_pragma(Bool_.Y, "wal_checkpoint" , "passive");}
public static Sqlite_pragma New__wal_checkpoint__full() {return new Sqlite_pragma(Bool_.Y, "wal_checkpoint" , "full");}
public static Sqlite_pragma New__wal_checkpoint__restart() {return new Sqlite_pragma(Bool_.Y, "wal_checkpoint" , "restart");}
public static Sqlite_pragma New__wal_checkpoint__truncate() {return new Sqlite_pragma(Bool_.Y, "wal_checkpoint" , "truncate");}
public static Sqlite_pragma New__locking_mode__normal() {return new Sqlite_pragma(Bool_.N, "locking_mode" , "normal");} // default
public static Sqlite_pragma New__locking_mode__exclusive() {return new Sqlite_pragma(Bool_.N, "locking_mode" , "exclusive");}
public static Sqlite_pragma New__page_size(int v) {return new Sqlite_pragma(Bool_.N, "page_size" , Int_.To_str(v));} // default is 1024
}

View File

@@ -0,0 +1,82 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.dbs.qrys.*;
import gplx.dbs.metas.*; import gplx.dbs.metas.parsers.*;
public class Sqlite_schema_mgr implements Dbmeta_reload_cmd {
private final Db_engine engine; private boolean init = true;
private final Dbmeta_idx_mgr idx_mgr = new Dbmeta_idx_mgr();
public Sqlite_schema_mgr(Db_engine engine) {
this.engine = engine;
this.tbl_mgr = new Dbmeta_tbl_mgr(this);
}
public Dbmeta_tbl_mgr Tbl_mgr() {
if (init) Init(engine);
return tbl_mgr;
} private final Dbmeta_tbl_mgr tbl_mgr;
public boolean Tbl_exists(String name) {
if (init) Init(engine);
return tbl_mgr.Has(name);
}
public boolean Fld_exists(String tbl, String fld) {
if (init) Init(engine);
Dbmeta_tbl_itm tbl_itm = tbl_mgr.Get_by(tbl);
return tbl_itm == null ? false : tbl_itm.Flds().Has(fld);
}
public boolean Idx_exists(String idx) {
if (init) Init(engine);
return idx_mgr.Has(idx);
}
public void Load_all() {
Init(engine);
}
private void Init(Db_engine engine) {
init = false;
tbl_mgr.Clear(); idx_mgr.Clear();
Dbmeta_parser__tbl tbl_parser = new Dbmeta_parser__tbl();
Dbmeta_parser__idx idx_parser = new Dbmeta_parser__idx();
Db_qry__select_in_tbl qry = Db_qry__select_in_tbl.new_("sqlite_master", String_.Ary_empty, String_.Ary("type", "name", "sql"), Db_qry__select_in_tbl.Order_by_null);
Db_rdr rdr = engine.Stmt_by_qry(qry).Exec_select__rls_auto();
try {
Gfo_usr_dlg_.Instance.Log_many("", "", "db.schema.load.bgn: conn=~{0}", engine.Conn_info().Db_api());
while (rdr.Move_next()) {
String type_str = rdr.Read_str("type");
String name = rdr.Read_str("name");
String sql = rdr.Read_str("sql");
try {
int type_int = Dbmeta_itm_tid.Xto_int(type_str);
switch (type_int) {
case Dbmeta_itm_tid.Tid_table:
if (String_.Has_at_bgn(name, "sqlite_")) continue; // ignore b/c of non-orthodox syntax; EX: "CREATE TABLE sqlite_sequence(name, seq)"; also "CREATE TABLE sqlite_stat(tbl,idx,stat)";
tbl_mgr.Add(tbl_parser.Parse(Bry_.new_u8(sql)));
break;
case Dbmeta_itm_tid.Tid_index:
if (sql == null) continue; // ignore "autoindex"; EX: sqlite_autoindex_temp_page_len_avg_1
idx_mgr.Add(idx_parser.Parse(Bry_.new_u8(sql)));
break;
default:
Gfo_usr_dlg_.Instance.Log_many("", "", "db.schema.unknown type: conn=~{0} type=~{1} name=~{2} sql=~{3}", engine.Conn_info().Db_api(), type_str, name, sql);
break;
}
} catch (Exception e) { // tables / indexes may be unparseable; skip them; EX: CREATE TABLE unparseable (col_1 /*comment*/ int); DATE:2016-06-08
Gfo_usr_dlg_.Instance.Log_many("", "", "db.schema.unparseable: conn=~{0} type=~{1} name=~{2} sql=~{3} err=~{4}", engine.Conn_info().Db_api(), type_str, name, sql, Err_.Message_gplx_log(e));
}
}
} finally {rdr.Rls();}
}
}

View File

@@ -0,0 +1,21 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Sqlite_tid {
public static final int Tid_int = 1, Tid_text = 2, Tid_none = 3, Tid_real = 4, Tid_numeric = 5;
}

View File

@@ -0,0 +1,71 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.sqlite; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.dbs.qrys.*;
public class Sqlite_txn_mgr {
private final List_adp txn_list = List_adp_.New();
public Sqlite_txn_mgr(Db_engine engine) {this.engine = engine;} private final Db_engine engine;
private boolean pragma_needed = Bool_.Y, txn_started = Bool_.N; // NOTE: txns only support 1 level; SQLite fails when nesting transactions; DATE:2015-03-11
public void Txn_bgn(String name) {
if (String_.Len_eq_0(name)) name = "unnamed";
if (pragma_needed) {
pragma_needed = false;
engine.Exec_as_obj(Db_qry_sql.xtn_("PRAGMA synchronous = OFF;"));
}
// Execute(Db_qry_sql.xtn_("PRAGMA ENCODING=\"UTF-8\";"));
// Execute(Db_qry_sql.xtn_("PRAGMA journal_mode = OFF;")); // will cause out of memory
// Execute(Db_qry_sql.xtn_("PRAGMA journal_mode = MEMORY;"));
// Execute(Db_qry_sql.xtn_("PRAGMA temp_store = MEMORY;"));
// Execute(Db_qry_sql.xtn_("PRAGMA locking_mode = EXCLUSIVE;"));
// Execute(Db_qry_sql.xtn_("PRAGMA cache_size=4000;")); // too many will also cause out of memory
if (txn_started) {
engine.Exec_as_obj(Db_qry_sql.xtn_(String_.Format("SAVEPOINT {0};", name)));
}
else {
txn_started = true;
engine.Exec_as_obj(Db_qry_sql.xtn_("BEGIN TRANSACTION;"));
}
txn_list.Add(name);
}
public String Txn_end() {
if (txn_list.Count() == 0) {Gfo_usr_dlg_.Instance.Warn_many("", "", "no txns in stack;"); return "";}
String txn_last = (String)List_adp_.Pop_last(txn_list);
if (txn_list.Count() == 0) {// no txns left; commit it
engine.Exec_as_obj(Db_qry_sql.xtn_("COMMIT TRANSACTION;"));
txn_started = false;
}
else
engine.Exec_as_obj(Db_qry_sql.xtn_(String_.Format("RELEASE SAVEPOINT {0};", txn_last)));
return txn_last;
}
public void Txn_cxl() {
if (txn_list.Count() == 0) {Gfo_usr_dlg_.Instance.Warn_many("", "", "no txns in stack;"); return;}
String txn_last = (String)List_adp_.Pop_last(txn_list);
if (txn_list.Count() == 0) {// no txns left; rollback
engine.Exec_as_obj(Db_qry_sql.xtn_("ROLLBACK TRANSACTION;"));
txn_started = false;
}
else
engine.Exec_as_obj(Db_qry_sql.xtn_(String_.Format("ROLBACK TRANSACTION TO SAVEPOINT {0};", txn_last)));
}
public void Txn_sav() {
if (txn_list.Count() == 0) {Gfo_usr_dlg_.Instance.Warn_many("", "", "no txns in stack;"); return;}
String name = (String)txn_list.Get_at(txn_list.Count() - 1);
this.Txn_end(); this.Txn_bgn(name);
}
}

View File

@@ -0,0 +1,32 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import org.junit.*;
public class TdbConnectInfo_tst {
@Test public void Full() {
Db_conn_info connectInfo = Db_conn_info_.parse("gplx_key=tdb;url=C:\\dir\\xmpl.tdb;format=dsv;");
tst_Parse(connectInfo, Io_url_.new_any_("C:\\dir\\xmpl.tdb"), "dsv");
}
@Test public void DefaultFormat() {
Db_conn_info connectInfo = Db_conn_info_.parse("gplx_key=tdb;url=C:\\dir\\xmpl.tdb"); // dsv Format inferred
tst_Parse(connectInfo, Io_url_.new_any_("C:\\dir\\xmpl.tdb"), "dsv");
}
void tst_Parse(Db_conn_info connectInfo, Io_url url, String format) {
Tfds.Eq(((Tdb_conn_info)connectInfo).Url(), url);
}
}

View File

@@ -0,0 +1,47 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class TdbDatabase {
public String Name() {return name;} public void Name_set(String v) {name = v;} private String name = "xmpl";
public Io_url DbUrl() {return dbInfo;} Io_url dbInfo;
public TdbFileList Files() {return files;} TdbFileList files;
public TdbTableList Tables() {return tables;} TdbTableList tables;
@gplx.Internal protected boolean IsNew() {return isNew;} @gplx.Internal protected void IsNew_set(boolean v) {isNew = v;} private boolean isNew;
@gplx.Internal protected TdbFile MakeFile(Io_url url) {
TdbFile rv = TdbFile.new_(FileId_next++, url);
files.Add(rv);
return rv;
}
@gplx.Internal protected TdbTable MakeTbl(String name, int fileId) {
TdbFile file = files.Get_by_or_fail(fileId);
TdbTable rv = TdbTable.new_(TableId_next++, name, file);
tables.Add(rv);
return rv;
}
public static TdbDatabase new_(Io_url dbInfo) {TdbDatabase rv = new TdbDatabase(); rv.ctor(dbInfo); return rv;}
void ctor(Io_url dbInfo) {
this.dbInfo = dbInfo;
TdbFile mainFile = TdbFile.new_(TdbFile.MainFileId, dbInfo);
files = TdbFileList.new_(dbInfo, mainFile);
tables = TdbTableList.new_(dbInfo);
}
int FileId_next = TdbFile.MainFileId + 1;
int TableId_next = 1;
// public static Io_url UrlOf(Db_conn_info url) {return Io_url_.new_any_(url.ServerName());}
}

View File

@@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*;
class TdbDbLoadMgr {
public TdbDatabase LoadTbls(Io_url dbInfo) {
TdbDatabase db = TdbDatabase.new_(dbInfo);
if (!Io_mgr.Instance.ExistsFil(dbInfo)) {
db.IsNew_set(true);
return db;
}
DataRdr rdr = MakeDataRdr(dbInfo);
LoadTblsByRdr(db, rdr);
return db;
}
public void LoadTbl(TdbDatabase db, TdbTable tbl) {
DataRdr rootRdr = MakeDataRdr(tbl.File().Path());
LoadTblsByRdr(db, rootRdr);
}
void LoadTblsByRdr(TdbDatabase db, DataRdr rootRdr) {
DataRdr rdr = rootRdr.Subs();
while (rdr.MoveNextPeer()) {
String name = rdr.NameOfNode();
if (String_.Eq(name, TdbFileList.StoreTblName)) db.Files().DataObj_Rdr(rdr);
else if (String_.Eq(name, TdbTableList.StoreTableName)) db.Tables().DataObj_Rdr(rdr, db.Files());
else db.Tables().Get_by_or_fail(rdr.NameOfNode()).DataObj_Rdr(rdr);
}
if (db.Files().Count() == 0) throw Err_.new_wo_type("fatal error: db has no files", "connectInfo", db.DbUrl());
}
DataRdr MakeDataRdr(Io_url fil) {
String text = Io_mgr.Instance.LoadFilStr(fil);
return TdbStores.rdr_(text);
}
public static TdbDbLoadMgr new_() {return new TdbDbLoadMgr();} TdbDbLoadMgr() {}
}

View File

@@ -0,0 +1,101 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import org.junit.*; import gplx.core.gfo_ndes.*; import gplx.core.type_xtns.*;
import gplx.core.stores.*; /*DsvDataRdr*/ import gplx.langs.dsvs.*; /*DsvDataWtr*/
public class TdbDbLoadMgr_tst {
@Before public void setup() {
Io_url dbInfo = Io_url_.mem_fil_("mem/dir/db0.dsv");
db = TdbDatabase.new_(dbInfo);
wtr = DsvDataWtr_.new_();
}
TdbDatabase db; TdbDbLoadMgr loadMgr = TdbDbLoadMgr.new_(); TdbDbSaveMgr saveMgr = TdbDbSaveMgr.new_();
DataRdr rdr; DataWtr wtr;
@Test public void ReadDbFiles() {
String raw = String_.Concat_lines_crlf
( "=======DIF======================, ,\" \",//"
, "_files, ,\" \",#"
, "==DEF==DIF======================, ,\" \",//"
, "int," + StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$"
, "id,url,format, ,\" \",@"
, "==DATA=DIF======================, ,\" \",//"
, "1,mem/dir/db0.dsv,dsv"
, "2,C:\\file.dsv,dsv"
);
rdr = rdr_(raw);
db.Files().DataObj_Rdr(rdr);
Tfds.Eq(db.Files().Count(), 2);
TdbFile file2 = db.Files().Get_by_or_fail(2);
Tfds.Eq(file2.Path().Raw(), "C:\\file.dsv");
db.Files().DataObj_Wtr(wtr);
Tfds.Eq(wtr.To_str(), raw);
}
@Test public void ReadDbTbls() {
String raw = String_.Concat_lines_crlf
( "=======DIF======================, ,\" \",//"
, "_tables, ,\" \",#"
, "==DEF==DIF======================, ,\" \",//"
, "int," + StringClassXtn.Key_const + ",int, ,\" \",$"
, "id,name,file_id, ,\" \",@"
, "==DATA=DIF======================, ,\" \",//"
, "1,tbl1,1"
);
rdr = rdr_(raw);
db.Tables().DataObj_Rdr(rdr, db.Files());
Tfds.Eq(db.Tables().Count(), 1);
TdbTable table = db.Tables().Get_by_or_fail("tbl1");
Tfds.Eq(table.Name(), "tbl1");
Tfds.Eq(table.File().Id(), 1);
db.Tables().DataObj_Wtr(wtr);
Tfds.Eq(wtr.To_str(), raw);
}
@Test public void ReadTbl() {
String raw = String_.Concat_lines_crlf
( "=======DIF======================, ,\" \",//"
, "tbl0, ,\" \",#"
, "==DEF==DIF======================, ,\" \",//"
, "int," + StringClassXtn.Key_const + ", ,\" \",$"
, "id,name, ,\" \",@"
, "==DATA=DIF======================, ,\" \",//"
, "0,me"
);
rdr = rdr_(raw);
db.MakeTbl("tbl0", TdbFile.MainFileId);
db.Tables().Get_by_or_fail(rdr.NameOfNode()).DataObj_Rdr(rdr);
Tfds.Eq(db.Tables().Count(), 1);
TdbTable tbl = db.Tables().Get_by_or_fail("tbl0");
Tfds.Eq(tbl.Rows().Count(), 1);
GfoNde row = tbl.Rows().FetchAt_asGfoNde(0);
Tfds.Eq(row.Read("id"), 0);
Tfds.Eq(row.Read("name"), "me");
tbl.DataObj_Wtr(wtr);
Tfds.Eq(wtr.To_str(), raw);
}
DataRdr rdr_(String raw) {
DataRdr rdr = DsvDataRdr_.dsv_(raw);
rdr.MoveNextPeer(); // must move next as cur is not set and ReadProcs assume cur is set
return rdr;
}
}

View File

@@ -0,0 +1,64 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*;
class TdbDbSaveMgr {
public void SaveDb(TdbDatabase db) {
for (Object filObj : db.Files()) {
TdbFile fil = (TdbFile)filObj;
SaveFile(db, fil);
}
}
public void SaveFile(TdbDatabase db, TdbFile fil) {
List_adp tbls = FetchTablesWithSamePath(db, fil.Path());
boolean isSaveNeeded = db.IsNew();
for (Object tblObj : tbls) {
TdbTable tbl = (TdbTable)tblObj;
if (tbl.IsDirty()) {
isSaveNeeded = true;
break;
}
}
if (isSaveNeeded) {
SaveTblsToFile(db, fil, tbls);
db.IsNew_set(false);
}
}
void SaveTblsToFile(TdbDatabase db, TdbFile fil, List_adp tbls) {
DataWtr wtr = TdbStores.wtr_();
if (fil.Id() == TdbFile.MainFileId) { // if MainFile, save critical Files and Tables data
db.Files().DataObj_Wtr(wtr);
db.Tables().DataObj_Wtr(wtr);
}
for (Object tblObj : tbls) {
TdbTable tbl = (TdbTable)tblObj;
tbl.DataObj_Wtr(wtr);
}
Io_mgr.Instance.SaveFilStr(fil.Path(), wtr.To_str());
}
List_adp FetchTablesWithSamePath(TdbDatabase db, Io_url filPath) {
List_adp list = List_adp_.New();
for (Object tblObj : db.Tables()) {
TdbTable tbl = (TdbTable)tblObj;
if (tbl.File().Path().Eq (filPath))
list.Add(tbl);
}
return list;
}
public static TdbDbSaveMgr new_() {return new TdbDbSaveMgr();} TdbDbSaveMgr() {}
}

View File

@@ -0,0 +1,77 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import org.junit.*; import gplx.core.stores.*;
import gplx.langs.dsvs.*; import gplx.core.type_xtns.*;
public class TdbDbSaveMgr_tst {
@Before public void setup() {
Io_url dbInfo = Io_url_.mem_fil_("mem/dir/db0.dsv");
db = TdbDatabase.new_(dbInfo);
wtr.Clear();
} TdbDatabase db; TdbDbSaveMgr saveMgr = TdbDbSaveMgr.new_(); DataWtr wtr = DsvDataWtr_.new_();
@Test public void WriteDbFils() {
String expd = String_.Concat_lines_crlf
( ""
, ""
, "================================, ,\" \",//"
, "_files, ,\" \",#"
, "================================, ,\" \",//"
, "int," + StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$"
, "id,url,format, ,\" \",@"
, "================================, ,\" \",//"
, "1,mem/dir/db0.dsv,dsv"
);
db.Files().DataObj_Wtr(wtr);
String actl = wtr.To_str();
Tfds.Eq(expd, actl);
}
@Test public void WriteDbTbls() {
String expd = String_.Concat_lines_crlf
( ""
, ""
, "================================, ,\" \",//"
, "_tables, ,\" \",#"
, "================================, ,\" \",//"
, "int," + StringClassXtn.Key_const + ",int, ,\" \",$"
, "id,name,file_id, ,\" \",@"
, "================================, ,\" \",//"
);
db.Tables().DataObj_Wtr(wtr);
String actl = wtr.To_str();
Tfds.Eq(expd, actl);
}
@Test public void WriteTbl() {
String expd = String_.Concat_lines_crlf
( ""
, ""
, "================================, ,\" \",//"
, "tbl, ,\" \",#"
, "================================, ,\" \",//"
, "int," + StringClassXtn.Key_const + ", ,\" \",$"
, "id,name, ,\" \",@"
, "================================, ,\" \",//"
);
TdbTable tbl = db.MakeTbl("tbl", TdbFile.MainFileId);
tbl.Flds().Add("id", IntClassXtn.Instance);
tbl.Flds().Add("name", StringClassXtn.Instance);
tbl.DataObj_Wtr(wtr);
String actl = wtr.To_str();
Tfds.Eq(expd, actl);
}
}

View File

@@ -0,0 +1,47 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.criterias.*; import gplx.core.lists.*; /*GfoNde*/ import gplx.dbs.qrys.*; import gplx.core.gfo_ndes.*;
class TdbDeleteWkr implements Db_qryWkr {
public Object Exec(Db_engine engineObj, Db_qry cmdObj) {
TdbEngine engine = TdbEngine.cast(engineObj); Db_qry_delete cmd = (Db_qry_delete)cmdObj;
TdbTable tbl = engine.FetchTbl(cmd.Base_table());
List_adp deleted = List_adp_.New();
int rv = 0;
if (cmd.Where() == Db_qry_delete.Where__null) {
rv = tbl.Rows().Count();
tbl.Rows().Clear();
}
else {
Criteria crt = cmd.Where();
for (int i = 0; i < tbl.Rows().Count(); i++) {
GfoNde row = tbl.Rows().FetchAt_asGfoNde(i);
if (crt.Matches(row))
deleted.Add(row);
}
for (int i = 0; i < deleted.Count(); i++) {
GfoNde row = (GfoNde)deleted.Get_at(i);
tbl.Rows().Del(row);
rv++;
}
}
if (rv > 0) tbl.IsDirty_set(true);
return rv;
}
public static TdbDeleteWkr new_() {TdbDeleteWkr rv = new TdbDeleteWkr(); return rv;}
}

View File

@@ -0,0 +1,97 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*; import gplx.dbs.metas.*; import gplx.dbs.conn_props.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.*; import gplx.dbs.qrys.bats.*;
public class TdbEngine implements Db_engine {
public String Tid() {return Tdb_conn_info.Tid_const;}
public Db_conn_info Conn_info() {return conn_info;} private Db_conn_info conn_info;
public Db_conn_props_mgr Props() {return props;} private final Db_conn_props_mgr props = new Db_conn_props_mgr();
public Db_batch_mgr Batch_mgr() {return batch_mgr;} private final Db_batch_mgr batch_mgr = new Db_batch_mgr();
public Sql_qry_wtr Sql_wtr() {return sql_wtr;} private final Sql_qry_wtr sql_wtr = Sql_qry_wtr_.New__basic();
public TdbDatabase Db() {return db;} TdbDatabase db;
public void Conn_open() {
Tdb_conn_info tdb_url = (Tdb_conn_info)conn_info;
String url_str = tdb_url.Server();
db = loadMgr.LoadTbls(Io_url_.new_any_(url_str));
}
public void Conn_term() {}
public void Txn_bgn(String name) {}
public String Txn_end() {return "";}
public void Txn_cxl() {}
public void Txn_sav() {}
public Db_engine New_clone(Db_conn_info conn_info) {
TdbEngine rv = new TdbEngine();
rv.CtorTdbEngine(conn_info);
rv.Conn_open();
return rv;
}
public Object Exec_as_obj(Db_qry qry) {
Db_qryWkr wkr = (Db_qryWkr)wkrs.Get_by_or_fail(qry.Tid());
return wkr.Exec(this, qry);
}
public Db_stmt Stmt_by_qry(Db_qry qry) {return new Db_stmt_sql().Parse(qry, sql_wtr.To_sql_str(qry, true));}
public Object Stmt_by_sql(String sql) {throw Err_.new_unimplemented();}
public Db_rdr Exec_as_rdr__rls_manual(Object rdr_obj, String sql) {return Db_rdr_.Empty;}
public Db_rdr Exec_as_rdr__rls_auto(Db_stmt stmt, Object rdr_obj, String sql) {return Db_rdr_.Empty;}
public DataRdr New_rdr(java.sql.ResultSet rdr, String sql) {return DataRdr_.Null;}
public TdbTable FetchTbl(String name) {
TdbTable tbl = db.Tables().Get_by_or_fail(name);
if (!tbl.IsLoaded()) loadMgr.LoadTbl(db, tbl);
return tbl;
}
public void FlushAll() {
saveMgr.SaveDb(db);
}
public void FlushTbl(TdbTable tbl) {
saveMgr.SaveFile(db, tbl.File());
}
public void Meta_tbl_create(Dbmeta_tbl_itm meta) {throw Err_.new_unimplemented();}
public void Meta_idx_create(Gfo_usr_dlg usr_dlg, Dbmeta_idx_itm... ary) {throw Err_.new_unimplemented();}
public void Meta_idx_delete(String idx) {throw Err_.new_unimplemented();}
public void Meta_fld_append(String tbl, Dbmeta_fld_itm fld) {throw Err_.new_unimplemented();}
public void Meta_tbl_delete(String tbl) {}
public boolean Meta_tbl_exists(String name) {return false;}
public boolean Meta_fld_exists(String tbl, String fld) {return false;}
public boolean Meta_idx_exists(String idx) {return false;}
public void Env_db_attach(String alias, Db_conn conn) {}
public void Env_db_attach(String alias, Io_url db_url) {}
public void Env_db_detach(String alias) {}
public Dbmeta_tbl_mgr Meta_mgr() {return meta_mgr;} private final Dbmeta_tbl_mgr meta_mgr = new Dbmeta_tbl_mgr(Dbmeta_reload_cmd_.Noop);
Hash_adp wkrs = Hash_adp_.New(); TdbDbLoadMgr loadMgr = TdbDbLoadMgr.new_(); TdbDbSaveMgr saveMgr = TdbDbSaveMgr.new_();
public static final TdbEngine Instance = new TdbEngine();
void CtorTdbEngine(Db_conn_info conn_info) {
this.conn_info = conn_info;
wkrs.Add(Db_qry_.Tid_select, TdbSelectWkr.Instance);
wkrs.Add(Db_qry_.Tid_insert, TdbInsertWkr.new_());
wkrs.Add(Db_qry_.Tid_update, TdbUpdateWkr.new_());
wkrs.Add(Db_qry_.Tid_delete, TdbDeleteWkr.new_());
wkrs.Add(Db_qry_.Tid_flush, TdbFlushWkr.new_());
}
public static TdbEngine as_(Object obj) {return obj instanceof TdbEngine ? (TdbEngine)obj : null;}
public static TdbEngine cast(Object obj) {try {return (TdbEngine)obj;} catch(Exception exc) {throw Err_.new_type_mismatch_w_exc(exc, TdbEngine.class, obj);}}
}
interface Db_qryWkr {
Object Exec(Db_engine engine, Db_qry cmd);
}
class Db_qryWkr_ {
public static final Db_qryWkr Null = new Db_qryWrk_null();
}
class Db_qryWrk_null implements Db_qryWkr {
public Object Exec(Db_engine engine, Db_qry cmd) {return null;}
}

View File

@@ -0,0 +1,31 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class TdbFile {
public int Id() {return id;} int id;
public Io_url Path() {return url;} Io_url url;
public static TdbFile new_(int id, Io_url url) {
TdbFile rv = new TdbFile();
rv.id = id; rv.url = url;
return rv;
}
public static final int MainFileId = 1;
public static TdbFile as_(Object obj) {return obj instanceof TdbFile ? (TdbFile)obj : null;}
public static TdbFile cast(Object obj) {try {return (TdbFile)obj;} catch(Exception exc) {throw Err_.new_type_mismatch_w_exc(exc, TdbFile.class, obj);}}
}

View File

@@ -0,0 +1,64 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.gfo_ndes.*; import gplx.core.type_xtns.*; import gplx.core.stores.*;
import gplx.core.lists.*; /*Ordered_hash_base*/ import gplx.langs.dsvs.*; /*DsvStoreLayout*/
public class TdbFileList extends Ordered_hash_base {
public TdbFile Get_by_or_fail(int id) {return TdbFile.as_(Get_by_or_fail_base(id));}
public void Add(TdbFile src) {Add_base(src.Id(), src);}
Io_url dbInfo;
public static TdbFileList new_(Io_url dbInfo, TdbFile mainFile) {
TdbFileList rv = new TdbFileList();
rv.dbInfo = dbInfo;
rv.Add(mainFile);
rv.layout = DsvStoreLayout.dsv_full_();
return rv;
} TdbFileList() {}
@gplx.Internal protected void DataObj_Wtr(DataWtr wtr) {
wtr.InitWtr(DsvStoreLayout.Key_const, layout);
wtr.WriteTableBgn(StoreTblName, FldList);
for (Object filObj : this) {
TdbFile fil = (TdbFile)filObj;
wtr.WriteLeafBgn("fil");
wtr.WriteData(Fld_id, fil.Id());
wtr.WriteData(Fld_path, fil.Path());
wtr.WriteData("format", "dsv");
wtr.WriteLeafEnd();
}
wtr.WriteNodeEnd();
}
@gplx.Internal protected void DataObj_Rdr(DataRdr rdr) {
layout = TdbStores.FetchLayout(rdr);
this.Clear();
DataRdr subRdr = rdr.Subs();
while (subRdr.MoveNextPeer()) {
int id = subRdr.ReadInt(Fld_id);
String url = subRdr.ReadStrOr(Fld_path, dbInfo.Raw());
TdbFile file = (id == TdbFile.MainFileId)
? TdbFile.new_(TdbFile.MainFileId, dbInfo) // not redundant; prevents error of MainFile in different url/format than connectInfo
: TdbFile.new_(id, Io_url_.new_any_(url));
this.Add(file);
}
}
DsvStoreLayout layout;
public static final String StoreTblName = "_files";
static final String Fld_id = "id"; static final String Fld_path = "url";
static final GfoFldList FldList = GfoFldList_.new_().Add(Fld_id, IntClassXtn.Instance).Add(Fld_path, StringClassXtn.Instance).Add("format", StringClassXtn.Instance);
}

View File

@@ -0,0 +1,34 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.lists.*; /*GfoNde*/ import gplx.dbs.qrys.*;
class TdbFlushWkr implements Db_qryWkr {
public Object Exec(Db_engine engineObj, Db_qry cmdObj) {
TdbEngine engine = TdbEngine.cast(engineObj); Db_qry_flush cmd = Db_qry_flush.cast(cmdObj);
if (Array_.Len(cmd.TableNames()) == 0)
engine.FlushAll();
else {
for (String tblName : cmd.TableNames()) {
TdbTable tbl = engine.FetchTbl(tblName);
if (tbl.IsDirty()) engine.FlushTbl(tbl);
}
}
return 1;
}
public static TdbFlushWkr new_() {TdbFlushWkr rv = new TdbFlushWkr(); return rv;}
}

View File

@@ -0,0 +1,119 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import org.junit.*;
import gplx.core.ios.*; /*IoMgrFxt*/ import gplx.dbs.qrys.*; import gplx.core.type_xtns.*;
public class TdbFlush_tst {
@Before public void setup() {
Io_mgr.Instance.InitEngine_mem();
engine = fx_engine.run_MakeEngine(dbPath);
}
TdbEngine engine; Io_url dbPath = Io_url_.mem_fil_("mem/dir/db0.dsv"); DateAdp time = DateAdp_.parse_gplx("2001-01-01");
TdbEngineFxt fx_engine = TdbEngineFxt.new_(); IoMgrFxt fx_io = IoMgrFxt.new_();
@Test public void FlushNewDb() {
fx_engine.tst_FilesCount(engine, 1);
fx_engine.tst_File(engine, 0, TdbFile.MainFileId, Io_url_.mem_fil_("mem/dir/db0.dsv"), "dsv");
fx_io.tst_Exists(false, dbPath);
engine.FlushAll();
fx_io.tst_Exists(true, dbPath);
}
@Test public void IgnoreFlushedDb() {
engine.FlushAll();
fx_io.tst_Exists(true, dbPath);
fx_io.run_UpdateFilModifiedTime(dbPath, time);
engine.FlushAll();
fx_io.tst_QueryFilModified(true, dbPath, time);
}
@Test public void FlushNewTbl() {
engine.FlushAll();
fx_engine.run_MakeTbl(engine, "tbl0", TdbFile.MainFileId);
fx_io.run_UpdateFilModifiedTime(dbPath, time);
engine.FlushAll();
fx_io.tst_QueryFilModified(false, dbPath, time);
}
@Test public void IgnoreFlushedTbl() {
fx_engine.run_MakeTbl(engine, "tbl0", TdbFile.MainFileId);
engine.FlushAll();
fx_io.run_UpdateFilModifiedTime(dbPath, time);
engine.FlushAll();
fx_io.tst_QueryFilModified(true, dbPath, time);
}
@Test public void FlushDirtyTbl() {
fx_engine.run_MakeTbl(engine, "tbl0", TdbFile.MainFileId);
engine.FlushAll();
fx_io.run_UpdateFilModifiedTime(dbPath, time);
fx_engine.run_InsertRow(engine, "tbl0", 1);
engine.FlushAll();
fx_io.tst_QueryFilModified(false, dbPath, time);
}
@Test public void FlushDirtyFilOnly() {
Io_url dbPathOther = Io_url_.mem_fil_("mem/dir/db1.dsv");
TdbFile filOther = fx_engine.run_MakeFile(engine, dbPathOther); Tfds.Eq(false, Object_.Eq(filOther.Id(), TdbFile.MainFileId));
fx_engine.run_MakeTbl(engine, "tbl0", TdbFile.MainFileId); fx_engine.run_MakeTbl(engine, "tbl1", filOther.Id());
engine.FlushAll();
fx_io.run_UpdateFilModifiedTime(dbPath, time); fx_io.run_UpdateFilModifiedTime(dbPathOther, time);
fx_engine.run_InsertRow(engine, "tbl1", 1);
engine.FlushAll();
fx_io.tst_QueryFilModified(true, dbPath, time);
fx_io.tst_QueryFilModified(false, dbPathOther, time);
}
}
class TdbEngineFxt {
public TdbEngine run_MakeEngine(Io_url url) {
Db_conn_info connectInfo = Db_conn_info_.tdb_(url);
TdbEngine engine = (TdbEngine)TdbEngine.Instance.New_clone(connectInfo);
engine.Conn_open();
return engine;
}
public TdbFile run_MakeFile(TdbEngine engine, Io_url url) {return engine.Db().MakeFile(url);}
public TdbTable run_MakeTbl(TdbEngine engine, String tblName, int srcId) {
TdbTable rv = engine.Db().MakeTbl(tblName, srcId);
rv.Flds().Add("id", IntClassXtn.Instance);
return rv;
}
public void run_InsertRow(TdbEngine engine, String tblName, int idVal) {
Db_qry_insert cmd = new Db_qry_insert(tblName);
cmd.Val_int("id", idVal);
engine.Exec_as_obj(cmd);
}
public void tst_FilesCount(TdbEngine engine, int count) {Tfds.Eq(engine.Db().Files().Count(), count);}
public void tst_File(TdbEngine engine, int index, int id, Io_url url, String format) {
TdbFile src = engine.Db().Files().Get_by_or_fail(id);
Tfds.Eq(src.Path().Raw(), url.Raw());
}
public static TdbEngineFxt new_() {return new TdbEngineFxt();} TdbEngineFxt() {}
}
class IoMgrFxt {
public void run_UpdateFilModifiedTime(Io_url url, DateAdp val) {Io_mgr.Instance.UpdateFilModifiedTime(url, val);}
public void tst_QueryFilModified(boolean expdMatch, Io_url url, DateAdp expt) {
IoItmFil filItem = Io_mgr.Instance.QueryFil(url);
DateAdp actl = filItem.ModifiedTime();
boolean actlMatch = String_.Eq(expt.XtoStr_gplx(), actl.XtoStr_gplx());
Tfds.Eq(expdMatch, actlMatch, expt.XtoStr_gplx() + (expdMatch ? "!=" : "==") + actl.XtoStr_gplx());
}
public void tst_Exists(boolean expd, Io_url url) {Tfds.Eq(expd, Io_mgr.Instance.ExistsFil(url));}
public static IoMgrFxt new_() {return new IoMgrFxt();} IoMgrFxt() {}
}

View File

@@ -0,0 +1,68 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.gfo_ndes.*; import gplx.core.stores.*;
import gplx.core.lists.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.*; import gplx.dbs.sqls.itms.*;
class TdbInsertWkr implements Db_qryWkr {
public Object Exec(Db_engine engineObj, Db_qry cmdObj) {
TdbEngine engine = TdbEngine.cast(engineObj); Db_qry_insert cmd = (Db_qry_insert)cmdObj;
TdbTable tbl = engine.FetchTbl(cmd.Base_table());
tbl.IsDirty_set(true);
return cmd.Select() == null
? InsertRowsByVals(engine, tbl, cmd)
: InsertRowsBySelect(engine, tbl, cmd);
}
int InsertRowsBySelect(TdbEngine engine, TdbTable tbl, Db_qry_insert insert) {
int count = 0;
DataRdr rdr = (DataRdr)TdbSelectWkr.Instance.Exec(engine, insert.Select());
Sql_select_fld_list insertFlds = insert.Cols(); int insertFldsCount = insertFlds.Len();
GfoFldList selectFldsForNewRow = null;
try {selectFldsForNewRow = TdbSelectWkr.To_GfoFldLst(tbl, insertFlds);}
catch (Exception e) {throw Err_.new_exc(e, "db", "failed to generate flds for new row");}
if (insertFldsCount > selectFldsForNewRow.Count()) throw Err_.new_wo_type("insert flds cannot exceed selectFlds", "insertFlds", To_str(insertFlds), "selectFlds", selectFldsForNewRow.To_str());
while (rdr.MoveNextPeer()) {
count++;
GfoNde row = GfoNde_.vals_(selectFldsForNewRow, new Object[insertFldsCount]);
for (int i = 0; i < insertFldsCount; i++) {
row.WriteAt(i, rdr.ReadAt(i)); // NOTE: SELECT and INSERT flds are in same order; ex: INSERT INTO (a, b) SELECT (b, a)
}
tbl.Rows().Add(row);
}
return count;
}
int InsertRowsByVals(TdbEngine engine, TdbTable tbl, Db_qry_insert insert) {
GfoNde row = GfoNde_.vals_(tbl.Flds(), new Object[tbl.Flds().Count()]);
for (int i = 0; i < insert.Args().Count(); i++) {
Keyval kv = insert.Args().Get_at(i);
Db_arg arg = (Db_arg)kv.Val();
row.Write(kv.Key(), arg.Val);
}
tbl.Rows().Add(row);
return 1;
}
private String To_str(Sql_select_fld_list flds) {
Bry_bfr bfr = Bry_bfr_.New();
for (int i = 0; i < flds.Len(); i++) {
Sql_select_fld fld = flds.Get_at(i);
bfr.Add_str_u8(String_.Format("{0},{1}|", fld.Fld, fld.Alias));
}
return bfr.To_str();
}
public static TdbInsertWkr new_() {TdbInsertWkr rv = new TdbInsertWkr(); return rv;}
}

View File

@@ -0,0 +1,113 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.criterias.*; import gplx.core.gfo_ndes.*; import gplx.dbs.qrys.*; import gplx.dbs.sqls.*; import gplx.dbs.sqls.itms.*;
import gplx.core.lists.*; /*ComparerAble*/ import gplx.core.stores.*; /*GfoNdeRdr*/
class TdbSelectWkr implements Db_qryWkr {
public Object Exec(Db_engine engineObj, Db_qry cmdObj) {
TdbEngine engine = TdbEngine.cast(engineObj); Db_qry__select_cmd cmd = (Db_qry__select_cmd)cmdObj;
if (cmd.From().Tbls.Count() > 1) throw Err_.new_("gplx.tdbs", "joins not supported for tdbs", "sql", cmd.To_sql__exec(engineObj.Sql_wtr()));
TdbTable tbl = engine.FetchTbl(cmd.From().Base_tbl.Name);
GfoNdeList rv = (cmd.Where_itm() == Sql_where_clause.Where__null && cmd.Limit() == Db_qry__select_cmd.Limit__disabled) ? rv = tbl.Rows() : FilterRecords(tbl, cmd.Where_itm().Root, cmd.Limit());
if (cmd.GroupBy() != null)
rv = TdbGroupByWkr.GroupByExec(cmd, rv, tbl);
if (cmd.Order() != null) { // don't use null pattern here; if null ORDER BY, then don't call .Sort on GfoNdeList
ComparerAble comparer = Sql_order_fld_sorter.new_(cmd.Order().Flds());
rv.Sort_by(comparer);
}
return GfoNdeRdr_.peers_(rv, false);
}
GfoNdeList FilterRecords(TdbTable tbl, Criteria crt, int limit) {
GfoNdeList rv = GfoNdeList_.new_();
int count = 0;
for (int i = 0; i < tbl.Rows().Count(); i++) {
GfoNde row = (GfoNde)tbl.Rows().FetchAt_asGfoNde(i);
if (crt.Matches(row)) rv.Add(row);
++count;
if (count == limit) break;
}
return rv;
}
public static GfoFldList To_GfoFldLst(TdbTable tbl, Sql_select_fld_list flds) {
GfoFldList rv = GfoFldList_.new_();
int len = flds.Len();
for (int i = 0; i < len; ++i) {
Sql_select_fld selectFld = flds.Get_at(i);
GfoFld fld = tbl.Flds().FetchOrNull(selectFld.Fld);
if (fld == null) throw Err_.new_wo_type("fld not found in tbl", "fldName", selectFld.Fld, "tblName", tbl.Name(), "tblFlds", tbl.Flds().To_str());
if (rv.Has(selectFld.Alias)) throw Err_.new_wo_type("alias is not unique", "fldName", selectFld.Fld, "flds", rv.To_str());
selectFld.GroupBy_type(fld.Type());
rv.Add(selectFld.Alias, selectFld.Val_type());
}
return rv;
}
public static final TdbSelectWkr Instance = new TdbSelectWkr(); TdbSelectWkr() {}
}
class TdbGroupByWkr {
public static GfoNdeList GroupByExec(Db_qry__select_cmd select, GfoNdeList selectRows, TdbTable tbl) {
GfoNdeList rv = GfoNdeList_.new_();
Ordered_hash groupByHash = Ordered_hash_.New();
List_adp groupByFlds = select.GroupBy().Flds();
GfoFldList selectFldsForNewRow = TdbSelectWkr.To_GfoFldLst(tbl, select.Cols().Flds);
Sql_select_fld_list selectFlds = select.Cols().Flds;
for (int rowIdx = 0; rowIdx < selectRows.Count(); rowIdx++) {
GfoNde selectRow = selectRows.FetchAt_asGfoNde(rowIdx);
GfoNde groupByRow = FindOrNew(selectFldsForNewRow, groupByFlds, selectRow, groupByHash, rv);
int len = selectFlds.Len();
for (int i = 0; i < len; ++i) {
Sql_select_fld selectFld = selectFlds.Get_at(i);
Object val = groupByRow.Read(selectFld.Alias); // groupByRow is keyed by Alias; EX: Count(Id) AS CountOf
groupByRow.WriteAt(i, selectFld.GroupBy_eval(val, selectRow.Read(selectFld.Fld), selectFld.Val_type()));
}
}
return rv;
}
static GfoNde FindOrNew(GfoFldList selectFldsForNewRow, List_adp groupByFlds, GfoNde selectRow, Ordered_hash groupByRows, GfoNdeList rslt) {
int len = groupByFlds.Count();
Ordered_hash curHash = groupByRows;
GfoNde rv = null;
for (int i = 0; i < len; i++) {
String fld = (String)groupByFlds.Get_at(i);
boolean last = i == len - 1;
Object val = selectRow.Read(fld);
Object o = curHash.Get_by(val);
if (last) {
if (o == null) {
Object[] valAry = new Object[selectFldsForNewRow.Count()];
rv = GfoNde_.vals_(selectFldsForNewRow, valAry);
curHash.Add(val, rv);
rslt.Add(rv);
}
else
rv = GfoNde_.as_(o);
}
else {
if (o == null) {
Ordered_hash nextHash = Ordered_hash_.New();
curHash.Add(val, nextHash);
curHash = nextHash;
}
else {
curHash = (Ordered_hash)o;
}
}
}
return rv;
}
}

View File

@@ -0,0 +1,32 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.stores.*;
import gplx.core.stores.xmls.*; /*XmlDataRdr*/
import gplx.langs.dsvs.*; /*DsvDataWtr*/
import gplx.core.lists.*; /*GfoNdeRdr*/
class TdbStores {
public static final String Dsv = "dsv";
public static final String Xml = "xml";
public static DataRdr rdr_(String text) {return DsvDataRdr_.dsv_(text);}
public static DataWtr wtr_() {return DsvDataWtr_.new_();}
@gplx.Internal protected static DsvStoreLayout FetchLayout(DataRdr rdr) {
GfoNdeRdr ndeRdr = GfoNdeRdr_.as_(rdr); if (ndeRdr == null) return null; // can happen for non-Dsv Rdrs (ex: Xml)
return DsvStoreLayout.as_(ndeRdr.UnderNde().EnvVars().Get_by(DsvStoreLayout.Key_const));
}
}

View File

@@ -0,0 +1,65 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.*; /*GfoNdeList*/ import gplx.core.stores.*; import gplx.langs.dsvs.*; /*DsvStoreLayout*/ import gplx.core.gfo_ndes.*;
public class TdbTable {
public int Id() {return id;} int id;
public String Name() {return name;} private String name;
public GfoFldList Flds() {return flds;} GfoFldList flds = GfoFldList_.new_();
public GfoNdeList Rows() {return rows;} GfoNdeList rows = GfoNdeList_.new_();
@gplx.Internal protected TdbFile File() {return file;} TdbFile file;
@gplx.Internal protected boolean IsLoaded() {return isLoaded;} private boolean isLoaded = true;
@gplx.Internal protected boolean IsDirty() {return isDirty;} public void IsDirty_set(boolean v) {isDirty = v;} private boolean isDirty = false;
public static TdbTable new_(int id, String name, TdbFile file) {TdbTable rv = new TdbTable(); rv.ctor(id, name, file); rv.isDirty = true; return rv;} TdbTable() {}
public static TdbTable load_(int id, String name, TdbFile file) {TdbTable rv = new TdbTable(); rv.ctor(id, name, file); rv.isLoaded = false; return rv;}
void ctor(int id, String name, TdbFile file) {
this.id = id; this.name = name; this.file = file;
layout = DsvStoreLayout.dsv_full_();
}
@gplx.Internal protected void DataObj_Wtr(DataWtr wtr) {
wtr.InitWtr(DsvStoreLayout.Key_const, layout);
wtr.WriteTableBgn(name, flds);
for (int rowIdx = 0; rowIdx < rows.Count(); rowIdx++) {
GfoNde drow = rows.FetchAt_asGfoNde(rowIdx);
wtr.WriteLeafBgn("row");
for (int i = 0; i < drow.Flds().Count(); i++)
wtr.WriteData(drow.Flds().Get_at(i).Key(), drow.ReadAt(i));
wtr.WriteLeafEnd();
}
wtr.WriteNodeEnd();
isDirty = false;
}
@gplx.Internal protected void DataObj_Rdr(DataRdr rdr) {
layout = TdbStores.FetchLayout(rdr);
GfoNdeRdr ndeRdr = GfoNdeRdr_.as_(rdr );
if (ndeRdr != null) {
if (ndeRdr.UnderNde() == null) throw Err_.new_wo_type("ndeRdr.UnderNde is null", "name", rdr.NameOfNode());
rows = ndeRdr.UnderNde().Subs();
flds = ndeRdr.UnderNde().SubFlds();
}
else { // XmlRdr needs to load each row again...
throw Err_.new_invalid_op("TableLoad not implemented").Args_add("rdrType", Type_adp_.NameOf_obj(rdr), "rdrName", rdr.NameOfNode());
}
isLoaded = true;
}
DsvStoreLayout layout;
public static TdbTable as_(Object obj) {return obj instanceof TdbTable ? (TdbTable)obj : null;}
public static TdbTable cast(Object obj) {try {return (TdbTable)obj;} catch(Exception exc) {throw Err_.new_type_mismatch_w_exc(exc, TdbTable.class, obj);}}
}

View File

@@ -0,0 +1,63 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.lists.*; /*Ordered_hash_base*/ import gplx.langs.dsvs.*; /*DsvStoreLayout*/ import gplx.core.gfo_ndes.*; import gplx.core.type_xtns.*; import gplx.core.stores.*;
public class TdbTableList extends Ordered_hash_base {
public TdbTable Get_by(String name) {return TdbTable.as_(Fetch_base(name));}
public TdbTable Get_by_or_fail(String name) {
TdbTable rv = TdbTable.as_(Get_by(name)); if (rv == null) throw Err_.new_wo_type("could not find table; database file may not exist", "table", name);
return rv;
}
public void Add(TdbTable dataTable) {Add_base(dataTable.Name(), dataTable);}
public static TdbTableList new_(Io_url dbInfo) {
TdbTableList rv = new TdbTableList();
rv.layout = DsvStoreLayout.dsv_full_();
return rv;
}
@gplx.Internal protected void DataObj_Wtr(DataWtr wtr) {
wtr.InitWtr(DsvStoreLayout.Key_const, layout);
wtr.WriteTableBgn(StoreTableName, FldList);
for (Object tblObj : this) {
TdbTable tbl = (TdbTable)tblObj;
wtr.WriteLeafBgn("tbl");
wtr.WriteData(Fld_id, tbl.Id());
wtr.WriteData(Fld_name, tbl.Name());
wtr.WriteData(Fld_file_id, tbl.File().Id());
wtr.WriteLeafEnd();
}
wtr.WriteNodeEnd();
}
@gplx.Internal protected void DataObj_Rdr(DataRdr rdr, TdbFileList files) {
layout = TdbStores.FetchLayout(rdr);
DataRdr subRdr = rdr.Subs();
this.Clear();
while (subRdr.MoveNextPeer()) {
int id = subRdr.ReadInt(Fld_id);
String name = subRdr.ReadStr(Fld_name);
int file_id = subRdr.ReadInt(Fld_file_id);
TdbFile file = files.Get_by_or_fail(file_id);
TdbTable table = TdbTable.load_(id, name, file);
this.Add(table);
}
}
DsvStoreLayout layout;
public static final String StoreTableName = "_tables";
static final String Fld_id = "id"; static final String Fld_name = "name"; static final String Fld_file_id = "file_id";
static final GfoFldList FldList = GfoFldList_.new_().Add(Fld_id, IntClassXtn.Instance).Add(Fld_name, StringClassXtn.Instance).Add(Fld_file_id, IntClassXtn.Instance);
}

View File

@@ -0,0 +1,46 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
import gplx.core.criterias.*; import gplx.core.lists.*; /*GfoNde*/ import gplx.core.gfo_ndes.*;
import gplx.dbs.qrys.*;
class TdbUpdateWkr implements Db_qryWkr {
public Object Exec(Db_engine engineObj, Db_qry cmdObj) {
TdbEngine engine = TdbEngine.cast(engineObj); Db_qry_update cmd = (Db_qry_update)cmdObj;
int rv = 0;
TdbTable tbl = engine.FetchTbl(cmd.Base_table());
Criteria crt = cmd.Where();
for (int i = 0; i < tbl.Rows().Count(); i++) {
GfoNde row = (GfoNde)tbl.Rows().FetchAt_asGfoNde(i);
if (crt.Matches(row)) {
UpdateRow(cmd, row);
rv++;
}
}
if (rv > 0) tbl.IsDirty_set(true);
return rv;
}
void UpdateRow(Db_qry_update cmd, GfoNde row) {
for (int i = 0; i < cmd.Args().Count(); i++) {
Keyval p = (Keyval)cmd.Args().Get_at(i);
Db_arg prm = (Db_arg)p.Val();
row.Write(p.Key(), prm.Val);
}
}
public static TdbUpdateWkr new_() {TdbUpdateWkr rv = new TdbUpdateWkr(); return rv;}
}

View File

@@ -0,0 +1,37 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package gplx.dbs.engines.tdbs; import gplx.*; import gplx.dbs.*; import gplx.dbs.engines.*;
public class Tdb_conn_info extends Db_conn_info__base {
public Tdb_conn_info(String raw, String db_api, String database, Io_url url) {super(raw, db_api, database);this.url = url; this.server = url.Raw(); }
@Override public String Key() {return Tid_const;} public static final String Tid_const = "tdb";
public Io_url Url() {return url;} private final Io_url url;
public String Server() {return server;} private final String server;
@Override public Db_conn_info New_self(String raw, Keyval_hash hash) {
Io_url url = Io_url_.new_any_(hash.Get_val_as_str_or_fail("url"));
String db = url.NameOnly();
String api = Bld_api(hash, Keyval_.new_("version", "3"));
return new Tdb_conn_info(raw, api, db, url);
}
public static Db_conn_info new_(Io_url url) {
return Db_conn_info_.parse(Bld_raw
( "gplx_key", Tid_const
, "url", url.Raw()
));
}
public static final Tdb_conn_info Instance = new Tdb_conn_info("", "", "", Io_url_.Empty);
}