/ *
XOWA: the XOWA Offline Wiki Application
Copyright ( C ) 2012 - 2020 gnosygnu @gmail.com
XOWA is licensed under the terms of the General Public License ( GPL ) Version 3 ,
or alternatively under the terms of the Apache License Version 2.0 .
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case - by - case basis .
The terms of each license can be found in the source code repository :
GPLv3 License : https : //github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License : https : //github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
* /
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.consoles.Console_adp_ ;
import gplx.core.consoles.Console_adp__sys ;
import gplx.core.ios.IoItmFil ;
import gplx.dbs.wkrs.SqlWkrMgr ;
import gplx.dbs.wkrs.randoms.SqliteRandomWkr ;
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 ( ) ; }
public void CtorConn ( SqlWkrMgr wkrMgr ) {
wkrMgr . Set ( new SqliteRandomWkr ( ) ) ;
}
@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 ) ;
boolean read_only = sqlite_fs_itm . Exists ( ) // 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
& & Io_mgr . Instance . Query_read_only ( sqlite_fs_url , Sqlite_engine_ . Read_only_detection ) ;
Keyval [ ] props = read_only
? Keyval_ . Ary ( Keyval_ . new_ ( "open_mode" , "1" ) )
: Keyval_ . Ary_empty ;
if ( read_only ) {
Gfo_usr_dlg_ . Instance . Note_many ( "" , "" , "Sqlite db opened as read-only: url=~{0}" , sqlite_fs_url . Xto_api ( ) ) ;
}
// 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 ( ) ) ;
}
}