diff options
Diffstat (limited to 'sqlite-jdbc/src')
27 files changed, 12229 insertions, 0 deletions
diff --git a/sqlite-jdbc/src/main/java/SQLite/Authorizer.java b/sqlite-jdbc/src/main/java/SQLite/Authorizer.java new file mode 100644 index 0000000..cdc321d --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Authorizer.java @@ -0,0 +1,25 @@ +package SQLite; + +/** + * Callback interface for SQLite's authorizer function. + */ + +public interface Authorizer { + + /** + * Callback to authorize access. + * + * @param what integer indicating type of access + * @param arg1 first argument (table, view, index, or trigger name) + * @param arg2 second argument (file, table, or column name) + * @param arg3 third argument (database name) + * @param arg4 third argument (trigger name) + * @return Constants.SQLITE_OK for success, Constants.SQLITE_IGNORE + * for don't allow access but don't raise an error, Constants.SQLITE_DENY + * for abort SQL statement with error. + */ + + public int authorize(int what, String arg1, String arg2, String arg3, + String arg4); +} + diff --git a/sqlite-jdbc/src/main/java/SQLite/Blob.java b/sqlite-jdbc/src/main/java/SQLite/Blob.java new file mode 100644 index 0000000..3de9f8a --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Blob.java @@ -0,0 +1,323 @@ +package SQLite; + +import java.io.*; + +/** + * Internal class implementing java.io.InputStream on + * SQLite 3.4.0 incremental blob I/O interface. + */ + +class BlobR extends InputStream { + + /** + * Blob instance + */ + + private Blob blob; + + /** + * Read position, file pointer. + */ + + private int pos; + + /** + * Contruct InputStream from blob instance. + */ + + BlobR(Blob blob) { + this.blob = blob; + this.pos = 0; + } + + /** + * Return number of available bytes for reading. + * @return available input bytes + */ + + public int available() throws IOException { + int ret = blob.size - pos; + return (ret < 0) ? 0 : ret; + } + + /** + * Mark method; dummy to satisfy InputStream class. + */ + + public void mark(int limit) { + } + + /** + * Reset method; dummy to satisfy InputStream class. + */ + + public void reset() throws IOException { + } + + /** + * Mark support; not for this class. + * @return always false + */ + + public boolean markSupported() { + return false; + } + + /** + * Close this blob InputStream. + */ + + public void close() throws IOException { + blob.close(); + blob = null; + pos = 0; + } + + /** + * Skip over blob data. + */ + + public long skip(long n) throws IOException { + long ret = pos + n; + if (ret < 0) { + ret = 0; + pos = 0; + } else if (ret > blob.size) { + ret = blob.size; + pos = blob.size; + } else { + pos = (int) ret; + } + return ret; + } + + /** + * Read single byte from blob. + * @return byte read + */ + + public int read() throws IOException { + byte b[] = new byte[1]; + int n = blob.read(b, 0, pos, b.length); + if (n > 0) { + pos += n; + return b[0]; + } + return -1; + } + + /** + * Read byte array from blob. + * @param b byte array to be filled + * @return number of bytes read + */ + + public int read(byte b[]) throws IOException { + int n = blob.read(b, 0, pos, b.length); + if (n > 0) { + pos += n; + return n; + } + return -1; + } + + /** + * Read slice of byte array from blob. + * @param b byte array to be filled + * @param off offset into byte array + * @param len length to be read + * @return number of bytes read + */ + + public int read(byte b[], int off, int len) throws IOException { + if (off + len > b.length) { + len = b.length - off; + } + if (len < 0) { + return -1; + } + if (len == 0) { + return 0; + } + int n = blob.read(b, off, pos, len); + if (n > 0) { + pos += n; + return n; + } + return -1; + } +} + +/** + * Internal class implementing java.io.OutputStream on + * SQLite 3.4.0 incremental blob I/O interface. + */ + +class BlobW extends OutputStream { + + /** + * Blob instance + */ + + private Blob blob; + + /** + * Read position, file pointer. + */ + + private int pos; + + /** + * Contruct OutputStream from blob instance. + */ + + BlobW(Blob blob) { + this.blob = blob; + this.pos = 0; + } + + /** + * Flush blob; dummy to satisfy OutputStream class. + */ + + public void flush() throws IOException { + } + + /** + * Close this blob OutputStream. + */ + + public void close() throws IOException { + blob.close(); + blob = null; + pos = 0; + } + + /** + * Write blob data. + * @param v byte to be written at current position. + */ + + public void write(int v) throws IOException { + byte b[] = new byte[1]; + b[0] = (byte) v; + pos += blob.write(b, 0, pos, 1); + } + + /** + * Write blob data. + * @param b byte array to be written at current position. + */ + + public void write(byte[] b) throws IOException { + if (b != null && b.length > 0) { + pos += blob.write(b, 0, pos, b.length); + } + } + + /** + * Write blob data. + * @param b byte array to be written. + * @param off offset within byte array + * @param len length of data to be written + */ + + public void write(byte[] b, int off, int len) throws IOException { + if (b != null) { + if (off + len > b.length) { + len = b.length - off; + } + if (len <= 0) { + return; + } + pos += blob.write(b, off, pos, len); + } + } +} + +/** + * Class to represent SQLite3 3.4.0 incremental blob I/O interface. + * + * Note, that all native methods of this class are + * not synchronized, i.e. it is up to the caller + * to ensure that only one thread is in these + * methods at any one time. + */ + +public class Blob { + + /** + * Internal handle for the SQLite3 blob. + */ + + private long handle = 0; + + /** + * Cached size of blob, setup right after blob + * has been opened. + */ + + protected int size = 0; + + /** + * Return InputStream for this blob + * @return InputStream + */ + + public InputStream getInputStream() { + return (InputStream) new BlobR(this); + } + + /** + * Return OutputStream for this blob + * @return OutputStream + */ + + public OutputStream getOutputStream() { + return (OutputStream) new BlobW(this); + } + + /** + * Close blob. + */ + + public native void close(); + + /** + * Internal blob write method. + * @param b byte array to be written + * @param off offset into byte array + * @param pos offset into blob + * @param len length to be written + * @return number of bytes written to blob + */ + + native int write(byte[] b, int off, int pos, int len) throws IOException; + + /** + * Internal blob read method. + * @param b byte array to be written + * @param off offset into byte array + * @param pos offset into blob + * @param len length to be written + * @return number of bytes written to blob + */ + + native int read(byte[] b, int off, int pos, int len) throws IOException; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/BusyHandler.java b/sqlite-jdbc/src/main/java/SQLite/BusyHandler.java new file mode 100644 index 0000000..c39b39d --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/BusyHandler.java @@ -0,0 +1,20 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined busy handler. + */ + +public interface BusyHandler { + + /** + * Invoked when a table is locked by another process + * or thread. The method should return true for waiting + * until the table becomes unlocked, or false in order + * to abandon the action.<BR><BR> + * + * @param table the name of the locked table + * @param count number of times the table was locked + */ + + public boolean busy(String table, int count); +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Callback.java b/sqlite-jdbc/src/main/java/SQLite/Callback.java new file mode 100644 index 0000000..3eeb605 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Callback.java @@ -0,0 +1,68 @@ +package SQLite; + +/** + * Callback interface for SQLite's query results. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * class TableFmt implements SQLite.Callback { + * public void columns(String cols[]) { + * System.out.println("<TH><TR>"); + * for (int i = 0; i < cols.length; i++) { + * System.out.println("<TD>" + cols[i] + "</TD>"); + * } + * System.out.println("</TR></TH>"); + * } + * public boolean newrow(String cols[]) { + * System.out.println("<TR>"); + * for (int i = 0; i < cols.length; i++) { + * System.out.println("<TD>" + cols[i] + "</TD>"); + * } + * System.out.println("</TR>"); + * return false; + * } + * } + * ... + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * System.out.println("<TABLE>"); + * db.exec("select * from TEST", new TableFmt()); + * System.out.println("</TABLE>"); + * ... + * </PRE> + */ + +public interface Callback { + + /** + * Reports column names of the query result. + * This method is invoked first (and once) when + * the SQLite engine returns the result set.<BR><BR> + * + * @param coldata string array holding the column names + */ + + public void columns(String coldata[]); + + /** + * Reports type names of the columns of the query result. + * This is available from SQLite 2.6.0 on and needs + * the PRAGMA show_datatypes to be turned on.<BR><BR> + * + * @param types string array holding column types + */ + + public void types(String types[]); + + /** + * Reports row data of the query result. + * This method is invoked for each row of the + * result set. If true is returned the running + * SQLite query is aborted.<BR><BR> + * + * @param rowdata string array holding the column values of the row + */ + + public boolean newrow(String rowdata[]); +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Constants.java b/sqlite-jdbc/src/main/java/SQLite/Constants.java new file mode 100644 index 0000000..4e636b9 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Constants.java @@ -0,0 +1,157 @@ +/* DO NOT EDIT */ + +package SQLite; + +/** + * Container for SQLite constants. + */ + +public final class Constants { + /* + * Error code: 0 + */ + public static final int SQLITE_OK = 0; + /* + * Error code: 1 + */ + public static final int SQLITE_ERROR = 1; + /* + * Error code: 2 + */ + public static final int SQLITE_INTERNAL = 2; + /* + * Error code: 3 + */ + public static final int SQLITE_PERM = 3; + /* + * Error code: 4 + */ + public static final int SQLITE_ABORT = 4; + /* + * Error code: 5 + */ + public static final int SQLITE_BUSY = 5; + /* + * Error code: 6 + */ + public static final int SQLITE_LOCKED = 6; + /* + * Error code: 7 + */ + public static final int SQLITE_NOMEM = 7; + /* + * Error code: 8 + */ + public static final int SQLITE_READONLY = 8; + /* + * Error code: 9 + */ + public static final int SQLITE_INTERRUPT = 9; + /* + * Error code: 10 + */ + public static final int SQLITE_IOERR = 10; + /* + * Error code: 11 + */ + public static final int SQLITE_CORRUPT = 11; + /* + * Error code: 12 + */ + public static final int SQLITE_NOTFOUND = 12; + /* + * Error code: 13 + */ + public static final int SQLITE_FULL = 13; + /* + * Error code: 14 + */ + public static final int SQLITE_CANTOPEN = 14; + /* + * Error code: 15 + */ + public static final int SQLITE_PROTOCOL = 15; + /* + * Error code: 16 + */ + public static final int SQLITE_EMPTY = 16; + /* + * Error code: 17 + */ + public static final int SQLITE_SCHEMA = 17; + /* + * Error code: 18 + */ + public static final int SQLITE_TOOBIG = 18; + /* + * Error code: 19 + */ + public static final int SQLITE_CONSTRAINT = 19; + /* + * Error code: 20 + */ + public static final int SQLITE_MISMATCH = 20; + /* + * Error code: 21 + */ + public static final int SQLITE_MISUSE = 21; + /* + * Error code: 22 + */ + public static final int SQLITE_NOLFS = 22; + /* + * Error code: 23 + */ + public static final int SQLITE_AUTH = 23; + /* + * Error code: 24 + */ + public static final int SQLITE_FORMAT = 24; + /* + * Error code: 25 + */ + public static final int SQLITE_RANGE = 25; + /* + * Error code: 26 + */ + public static final int SQLITE_NOTADB = 26; + public static final int SQLITE_ROW = 100; + public static final int SQLITE_DONE = 101; + public static final int SQLITE_INTEGER = 1; + public static final int SQLITE_FLOAT = 2; + public static final int SQLITE_BLOB = 4; + public static final int SQLITE_NULL = 5; + public static final int SQLITE3_TEXT = 3; + public static final int SQLITE_NUMERIC = -1; + public static final int SQLITE_TEXT = 3; + public static final int SQLITE2_TEXT = -2; + public static final int SQLITE_ARGS = -3; + public static final int SQLITE_COPY = 0; + public static final int SQLITE_CREATE_INDEX = 1; + public static final int SQLITE_CREATE_TABLE = 2; + public static final int SQLITE_CREATE_TEMP_INDEX = 3; + public static final int SQLITE_CREATE_TEMP_TABLE = 4; + public static final int SQLITE_CREATE_TEMP_TRIGGER = 5; + public static final int SQLITE_CREATE_TEMP_VIEW = 6; + public static final int SQLITE_CREATE_TRIGGER = 7; + public static final int SQLITE_CREATE_VIEW = 8; + public static final int SQLITE_DELETE = 9; + public static final int SQLITE_DROP_INDEX = 10; + public static final int SQLITE_DROP_TABLE = 11; + public static final int SQLITE_DROP_TEMP_INDEX = 12; + public static final int SQLITE_DROP_TEMP_TABLE = 13; + public static final int SQLITE_DROP_TEMP_TRIGGER = 14; + public static final int SQLITE_DROP_TEMP_VIEW = 15; + public static final int SQLITE_DROP_TRIGGER = 16; + public static final int SQLITE_DROP_VIEW = 17; + public static final int SQLITE_INSERT = 18; + public static final int SQLITE_PRAGMA = 19; + public static final int SQLITE_READ = 20; + public static final int SQLITE_SELECT = 21; + public static final int SQLITE_TRANSACTION = 22; + public static final int SQLITE_UPDATE = 23; + public static final int SQLITE_ATTACH = 24; + public static final int SQLITE_DETACH = 25; + public static final int SQLITE_DENY = 1; + public static final int SQLITE_IGNORE = 2; +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Database.java b/sqlite-jdbc/src/main/java/SQLite/Database.java new file mode 100644 index 0000000..fbb5d29 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Database.java @@ -0,0 +1,615 @@ +package SQLite; + +/** + * Main class wrapping an SQLite database. + */ + +public class Database { + + /** + * Internal handle for the native SQLite API. + */ + + protected long handle = 0; + + /** + * Internal last error code for exec() methods. + */ + + protected int error_code = 0; + + /** + * Open an SQLite database file. + * + * @param filename the name of the database file + * @param mode open mode, currently ignored + */ + + public void open(String filename, int mode) throws SQLite.Exception { + synchronized(this) { + _open(filename, mode); + } + } + + private native void _open(String filename, int mode) + throws SQLite.Exception; + + /** + * Open SQLite auxiliary database file for temporary + * tables. + * + * @param filename the name of the auxiliary file or null + */ + + public void open_aux_file(String filename) throws SQLite.Exception { + synchronized(this) { + _open_aux_file(filename); + } + } + + private native void _open_aux_file(String filename) + throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected void finalize() { + synchronized(this) { + _finalize(); + } + } + + private native void _finalize(); + + /** + * Close the underlying SQLite database file. + */ + + public void close() throws SQLite.Exception { + synchronized(this) { + _close(); + } + } + + private native void _close() + throws SQLite.Exception; + + /** + * Execute an SQL statement and invoke callback methods + * for each row of the result set.<P> + * + * It the method fails, an SQLite.Exception is thrown and + * an error code is set, which later can be retrieved by + * the last_error() method. + * + * @param sql the SQL statement to be executed + * @param cb the object implementing the callback methods + */ + + public void exec(String sql, SQLite.Callback cb) throws SQLite.Exception { + synchronized(this) { + _exec(sql, cb); + } + } + + private native void _exec(String sql, SQLite.Callback cb) + throws SQLite.Exception; + + /** + * Execute an SQL statement and invoke callback methods + * for each row of the result set. Each '%q' or %Q in the + * statement string is substituted by its corresponding + * element in the argument vector. + * <BR><BR> + * Example:<BR> + * <PRE> + * String args[] = new String[1]; + * args[0] = "tab%"; + * db.exec("select * from sqlite_master where type like '%q'", + * null, args); + * </PRE> + * + * It the method fails, an SQLite.Exception is thrown and + * an error code is set, which later can be retrieved by + * the last_error() method. + * + * @param sql the SQL statement to be executed + * @param cb the object implementing the callback methods + * @param args arguments for the SQL statement, '%q' substitution + */ + + public void exec(String sql, SQLite.Callback cb, + String args[]) throws SQLite.Exception { + synchronized(this) { + _exec(sql, cb, args); + } + } + + private native void _exec(String sql, SQLite.Callback cb, String args[]) + throws SQLite.Exception; + + /** + * Return the row identifier of the last inserted + * row. + */ + + public long last_insert_rowid() { + synchronized(this) { + return _last_insert_rowid(); + } + } + + private native long _last_insert_rowid(); + + /** + * Abort the current SQLite operation. + */ + + public void interrupt() { + synchronized(this) { + _interrupt(); + } + } + + private native void _interrupt(); + + /** + * Return the number of changed rows for the last statement. + */ + + public long changes() { + synchronized(this) { + return _changes(); + } + } + + private native long _changes(); + + /** + * Establish a busy callback method which gets called when + * an SQLite table is locked. + * + * @param bh the object implementing the busy callback method + */ + + public void busy_handler(SQLite.BusyHandler bh) { + synchronized(this) { + _busy_handler(bh); + } + } + + private native void _busy_handler(SQLite.BusyHandler bh); + + /** + * Set the timeout for waiting for an SQLite table to become + * unlocked. + * + * @param ms number of millisecond to wait + */ + + public void busy_timeout(int ms) { + synchronized(this) { + _busy_timeout(ms); + } + } + + private native void _busy_timeout(int ms); + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @return result set + */ + + public TableResult get_table(String sql) throws SQLite.Exception { + TableResult ret = new TableResult(); + if (!is3()) { + exec(sql, ret); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql); + set_last_error(vm.error_code); + while (vm.step(ret)) { + set_last_error(vm.error_code); + } + vm.finalize(); + } + } + return ret; + } + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @param args arguments for the SQL statement, '%q' substitution + * @return result set + */ + + public TableResult get_table(String sql, String args[]) + throws SQLite.Exception { + TableResult ret = new TableResult(); + if (!is3()) { + exec(sql, ret, args); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql, args); + set_last_error(vm.error_code); + while (vm.step(ret)) { + set_last_error(vm.error_code); + } + vm.finalize(); + } + } + return ret; + } + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @param args arguments for the SQL statement, '%q' substitution + * @param tbl TableResult to receive result set + * @return result set + */ + + public void get_table(String sql, String args[], TableResult tbl) + throws SQLite.Exception { + tbl.clear(); + if (!is3()) { + exec(sql, tbl, args); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql, args); + while (vm.step(tbl)) { + } + vm.finalize(); + } + } + } + + /** + * See if an SQL statement is complete. + * Returns true if the input string comprises + * one or more complete SQL statements. + * + * @param sql the SQL statement to be checked + */ + + public synchronized static boolean complete(String sql) { + return _complete(sql); + } + + private native static boolean _complete(String sql); + + /** + * Return SQLite version number as string. + * Don't rely on this when both SQLite 2 and 3 are compiled + * into the native part. Use the class method in this case. + */ + + public native static String version(); + + /** + * Return SQLite version number as string. + * If the database is not open, <tt>unknown</tt> is returned. + */ + + public native String dbversion(); + + /** + * Create regular function. + * + * @param name the name of the new function + * @param nargs number of arguments to function + * @param f interface of function + */ + + public void create_function(String name, int nargs, Function f) { + synchronized(this) { + _create_function(name, nargs, f); + } + } + + private native void _create_function(String name, int nargs, Function f); + + /** + * Create aggregate function. + * + * @param name the name of the new function + * @param nargs number of arguments to function + * @param f interface of function + */ + + public void create_aggregate(String name, int nargs, Function f) { + synchronized(this) { + _create_aggregate(name, nargs, f); + } + } + + private native void _create_aggregate(String name, int nargs, Function f); + + /** + * Set function return type. Only available in SQLite 2.6.0 and + * above, otherwise a no-op. + * + * @param name the name of the function whose return type is to be set + * @param type return type code, e.g. SQLite.Constants.SQLITE_NUMERIC + */ + + public void function_type(String name, int type) { + synchronized(this) { + _function_type(name, type); + } + } + + private native void _function_type(String name, int type); + + /** + * Return the code of the last error occured in + * any of the exec() methods. The value is valid + * after an Exception has been reported by one of + * these methods. See the <A HREF="Constants.html">Constants</A> + * class for possible values. + * + * @return SQLite error code + */ + + public int last_error() { + return error_code; + } + + /** + * Internal: set error code. + * @param error_code new error code + */ + + protected void set_last_error(int error_code) { + this.error_code = error_code; + } + + /** + * Return last error message of SQLite3 engine. + * + * @return error string or null + */ + + public String error_message() { + synchronized(this) { + return _errmsg(); + } + } + + private native String _errmsg(); + + /** + * Return error string given SQLite error code (SQLite2). + * + * @param error_code the error code + * @return error string + */ + + public static native String error_string(int error_code); + + /** + * Set character encoding. + * @param enc name of encoding + */ + + public void set_encoding(String enc) throws SQLite.Exception { + synchronized(this) { + _set_encoding(enc); + } + } + + private native void _set_encoding(String enc) + throws SQLite.Exception; + + /** + * Set authorizer function. Only available in SQLite 2.7.6 and + * above, otherwise a no-op. + * + * @param auth the authorizer function + */ + + public void set_authorizer(Authorizer auth) { + synchronized(this) { + _set_authorizer(auth); + } + } + + private native void _set_authorizer(Authorizer auth); + + /** + * Set trace function. Only available in SQLite 2.7.6 and above, + * otherwise a no-op. + * + * @param tr the trace function + */ + + public void trace(Trace tr) { + synchronized(this) { + _trace(tr); + } + } + + private native void _trace(Trace tr); + + /** + * Compile and return SQLite VM for SQL statement. Only available + * in SQLite 2.8.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be compiled + * @return a Vm object + */ + + public Vm compile(String sql) throws SQLite.Exception { + synchronized(this) { + Vm vm = new Vm(); + vm_compile(sql, vm); + return vm; + } + } + + /** + * Compile and return SQLite VM for SQL statement. Only available + * in SQLite 3.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be compiled + * @param args arguments for the SQL statement, '%q' substitution + * @return a Vm object + */ + + public Vm compile(String sql, String args[]) throws SQLite.Exception { + synchronized(this) { + Vm vm = new Vm(); + vm_compile_args(sql, vm, args); + return vm; + } + } + + /** + * Prepare and return SQLite3 statement for SQL. Only available + * in SQLite 3.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be prepared + * @return a Stmt object + */ + + public Stmt prepare(String sql) throws SQLite.Exception { + synchronized(this) { + Stmt stmt = new Stmt(); + stmt_prepare(sql, stmt); + return stmt; + } + } + + /** + * Open an SQLite3 blob. Only available in SQLite 3.4.0 and above. + * @param db database name + * @param table table name + * @param column column name + * @param row row identifier + * @param rw if true, open for read-write, else read-only + * @return a Blob object + */ + + public Blob open_blob(String db, String table, String column, + long row, boolean rw) throws SQLite.Exception { + synchronized(this) { + Blob blob = new Blob(); + _open_blob(db, table, column, row, rw, blob); + return blob; + } + } + + /** + * Check type of open database. + * @return true if SQLite3 database + */ + + public native boolean is3(); + + /** + * Internal compile method. + * @param sql SQL statement + * @param vm Vm object + */ + + private native void vm_compile(String sql, Vm vm) + throws SQLite.Exception; + + /** + * Internal compile method, SQLite 3.0 only. + * @param sql SQL statement + * @param args arguments for the SQL statement, '%q' substitution + * @param vm Vm object + */ + + private native void vm_compile_args(String sql, Vm vm, String args[]) + throws SQLite.Exception; + + /** + * Internal SQLite3 prepare method. + * @param sql SQL statement + * @param stmt Stmt object + */ + + private native void stmt_prepare(String sql, Stmt stmt) + throws SQLite.Exception; + + /** + * Internal SQLite open blob method. + * @param db database name + * @param table table name + * @param column column name + * @param row row identifier + * @param rw if true, open for read-write, else read-only + * @param blob Blob object + */ + + private native void _open_blob(String db, String table, String column, + long row, boolean rw, Blob blob) + throws SQLite.Exception; + + /** + * Establish a progress callback method which gets called after + * N SQLite VM opcodes. + * + * @param n number of SQLite VM opcodes until callback is invoked + * @param p the object implementing the progress callback method + */ + + public void progress_handler(int n, SQLite.ProgressHandler p) { + synchronized(this) { + _progress_handler(n, p); + } + } + + private native void _progress_handler(int n, SQLite.ProgressHandler p); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + /** + * Static initializer to load the native part. + */ + + static { + try { + String path = System.getProperty("SQLite.library.path"); + if (path == null || path.length() == 0){ + System.loadLibrary("sqlite_jni"); + } else { + try { + java.lang.reflect.Method mapLibraryName; + Class param[] = new Class[1]; + param[0] = String.class; + mapLibraryName = System.class.getMethod("mapLibraryName", + param); + Object args[] = new Object[1]; + args[0] = "sqlite_jni"; + String mapped = (String) mapLibraryName.invoke(null, args); + System.load(path + java.io.File.separator + mapped); + } catch (Throwable t) { + System.loadLibrary("sqlite_jni"); + } + } + internal_init(); + } catch (Throwable t) { + System.err.println("Unable to load sqlite: " + t); + } + } +} + diff --git a/sqlite-jdbc/src/main/java/SQLite/Exception.java b/sqlite-jdbc/src/main/java/SQLite/Exception.java new file mode 100644 index 0000000..cc26b99 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Exception.java @@ -0,0 +1,18 @@ +package SQLite; + +/** + * Class for SQLite related exceptions. + */ + +public class Exception extends java.lang.Exception { + + /** + * Construct a new SQLite exception. + * + * @param string error message + */ + + public Exception(String string) { + super(string); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Function.java b/sqlite-jdbc/src/main/java/SQLite/Function.java new file mode 100644 index 0000000..5aa5e33 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Function.java @@ -0,0 +1,59 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined functions. + * Each callback method receives a + * <A HREF="FunctionContext.html">FunctionContext</A> object + * which is used to set the function result or error code. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * class SinFunc implements SQLite.Function { + * public void function(SQLite.FunctionContext fc, String args[]) { + * try { + * Double d = new Double(args[0]); + * fc.set_result(Math.sin(d.doubleValue())); + * } catch (Exception e) { + * fc.set_error("sin(" + args[0] + "):" + e); + * } + * } + * ... + * } + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * db.create_function("sin", 1, SinFunc); + * ... + * db.exec("select sin(1.0) from test", null); + * </PRE> + */ + +public interface Function { + + /** + * Callback for regular function. + * + * @param fc function's context for reporting result + * @param args String array of arguments + */ + + public void function(FunctionContext fc, String args[]); + + /** + * Callback for one step in aggregate function. + * + * @param fc function's context for reporting result + * @param args String array of arguments + */ + + public void step(FunctionContext fc, String args[]); + + /** + * Callback for final step in aggregate function. + * + * @param fc function's context for reporting result + */ + + public void last_step(FunctionContext fc); + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/FunctionContext.java b/sqlite-jdbc/src/main/java/SQLite/FunctionContext.java new file mode 100644 index 0000000..d0b5182 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/FunctionContext.java @@ -0,0 +1,82 @@ +package SQLite; + +/** + * Context for execution of SQLite's user defined functions. + * A reference to an instance of this class is passed to + * user defined functions. + */ + +public class FunctionContext { + + /** + * Internal handle for the native SQLite API. + */ + + private long handle = 0; + + /** + * Set function result from string. + * + * @param r result string + */ + + public native void set_result(String r); + + /** + * Set function result from integer. + * + * @param r result integer + */ + + public native void set_result(int r); + + /** + * Set function result from double. + * + * @param r result double + */ + + public native void set_result(double r); + + /** + * Set function result from error message. + * + * @param r result string (error message) + */ + + public native void set_error(String r); + + /** + * Set function result from byte array. + * Only provided by SQLite3 databases. + * + * @param r result byte array + */ + + public native void set_result(byte[] r); + + /** + * Set function result as empty blob given size. + * Only provided by SQLite3 databases. + * + * @param n size for empty blob + */ + + public native void set_result_zeroblob(int n); + + /** + * Retrieve number of rows for aggregate function. + */ + + public native int count(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCConnection.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCConnection.java new file mode 100644 index 0000000..20c98e3 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCConnection.java @@ -0,0 +1,452 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.*; + +public class JDBCConnection + implements java.sql.Connection, SQLite.BusyHandler { + + /** + * Open database. + */ + protected DatabaseX db; + + /** + * Database URL. + */ + protected String url; + + /** + * Character encoding. + */ + protected String enc; + + /** + * Autocommit flag, true means autocommit. + */ + protected boolean autocommit = true; + + /** + * In-transaction flag. + * Can be true only when autocommit false. + */ + protected boolean intrans = false; + + /** + * Timeout for Database.exec() + */ + protected int timeout = 1000000; + + /** + * File name of database. + */ + private String dbfile = null; + + /** + * Reference to meta data or null. + */ + private JDBCDatabaseMetaData meta = null; + + /** + * Base time value for timeout handling. + */ + private long t0; + + /** + * Database in readonly mode. + */ + private boolean readonly = false; + + + private boolean busy0(DatabaseX db, int count) { + if (count <= 1) { + t0 = System.currentTimeMillis(); + } + if (db != null) { + long t1 = System.currentTimeMillis(); + if (t1 - t0 > timeout) { + return false; + } + db.wait(100); + return true; + } + return false; + } + + public boolean busy(String table, int count) { + return busy0(db, count); + } + + protected boolean busy3(DatabaseX db, int count) { + if (count <= 1) { + t0 = System.currentTimeMillis(); + } + if (db != null) { + long t1 = System.currentTimeMillis(); + if (t1 - t0 > timeout) { + return false; + } + return true; + } + return false; + } + + private DatabaseX open(boolean readonly) throws SQLException { + DatabaseX db = null; + try { + db = new DatabaseX(); + db.open(dbfile, readonly ? 0444 : 0644); + db.set_encoding(enc); + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + int loop = 0; + while (true) { + try { + db.exec("PRAGMA short_column_names = off;", null); + db.exec("PRAGMA full_column_names = on;", null); + db.exec("PRAGMA empty_result_callbacks = on;", null); + if (SQLite.Database.version().compareTo("2.6.0") >= 0) { + db.exec("PRAGMA show_datatypes = on;", null); + } + } catch (SQLite.Exception e) { + if (db.last_error() != SQLite.Constants.SQLITE_BUSY || + !busy0(db, ++loop)) { + try { + db.close(); + } catch (SQLite.Exception ee) { + } + throw new SQLException(e.toString()); + } + continue; + } + break; + } + return db; + } + + public JDBCConnection(String url, String enc) throws SQLException { + if (url.startsWith("sqlite:/")) { + dbfile = url.substring(8); + } else if (url.startsWith("jdbc:sqlite:/")) { + dbfile = url.substring(13); + } else { + throw new SQLException("unsupported url"); + } + this.url = url; + this.enc = enc; + try { + db = open(readonly); + db.busy_handler(this); + } catch (SQLException e) { + if (db != null) { + try { + db.close(); + } catch (SQLite.Exception ee) { + } + } + throw e; + } + } + + /* non-standard */ + public SQLite.Database getSQLiteDatabase() { + return (SQLite.Database) db; + } + + public Statement createStatement() { + JDBCStatement s = new JDBCStatement(this); + return s; + } + + public Statement createStatement(int resultSetType, + int resultSetConcurrency) + throws SQLException { + JDBCStatement s = new JDBCStatement(this); + return s; + } + + public DatabaseMetaData getMetaData() throws SQLException { + if (meta == null) { + meta = new JDBCDatabaseMetaData(this); + } + return meta; + } + + public void close() throws SQLException { + try { + rollback(); + } catch (SQLException e) { + /* ignored */ + } + intrans = false; + if (db != null) { + try { + db.close(); + db = null; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + } + + public boolean isClosed() throws SQLException { + return db == null; + } + + public boolean isReadOnly() throws SQLException { + return readonly; + } + + public void clearWarnings() throws SQLException { + } + + public void commit() throws SQLException { + if (db == null) { + throw new SQLException("stale connection"); + } + if (!intrans) { + return; + } + try { + db.exec("COMMIT", null); + intrans = false; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + + public boolean getAutoCommit() throws SQLException { + return autocommit; + } + + public String getCatalog() throws SQLException { + return null; + } + + public int getTransactionIsolation() throws SQLException { + return TRANSACTION_SERIALIZABLE; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public String nativeSQL(String sql) throws SQLException { + throw new SQLException("not supported"); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + throw new SQLException("not supported"); + } + + public CallableStatement prepareCall(String sql, int x, int y) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql); + return s; + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency) + throws SQLException { + JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql); + return s; + } + + public void rollback() throws SQLException { + if (db == null) { + throw new SQLException("stale connection"); + } + if (!intrans) { + return; + } + try { + db.exec("ROLLBACK", null); + intrans = false; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + + public void setAutoCommit(boolean ac) throws SQLException { + if (ac && intrans && db != null) { + try { + db.exec("ROLLBACK", null); + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + intrans = false; + autocommit = ac; + } + + public void setCatalog(String catalog) throws SQLException { + } + + public void setReadOnly(boolean ro) throws SQLException { + if (intrans) { + throw new SQLException("incomplete transaction"); + } + if (ro != readonly) { + DatabaseX db = null; + try { + db = open(ro); + this.db.close(); + this.db = db; + db = null; + readonly = ro; + } catch (SQLException e) { + throw e; + } catch (SQLite.Exception ee) { + if (db != null) { + try { + db.close(); + } catch (SQLite.Exception eee) { + } + } + throw new SQLException(ee.toString()); + } + } + } + + public void setTransactionIsolation(int level) throws SQLException { + if (level != TRANSACTION_SERIALIZABLE) { + throw new SQLException("not supported"); + } + } + + public java.util.Map<String, Class<?>> getTypeMap() throws SQLException { + throw new SQLException("not supported"); + } + + public void setTypeMap(java.util.Map map) throws SQLException { + throw new SQLException("not supported"); + } + + public int getHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + + public void setHoldability(int holdability) throws SQLException { + if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) { + return; + } + throw new SQLException("not supported"); + } + + public Savepoint setSavepoint() throws SQLException { + throw new SQLException("not supported"); + } + + public Savepoint setSavepoint(String name) throws SQLException { + throw new SQLException("not supported"); + } + + public void rollback(Savepoint x) throws SQLException { + throw new SQLException("not supported"); + } + + public void releaseSavepoint(Savepoint x) throws SQLException { + throw new SQLException("not supported"); + } + + public Statement createStatement(int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) + throws SQLException { + if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) { + throw new SQLException("not supported"); + } + return createStatement(resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) + throws SQLException { + if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) { + throw new SQLException("not supported"); + } + return prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int x, int y, int z) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return prepareStatement(sql); + } + + public PreparedStatement prepareStatement(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql, String columns[]) + throws SQLException { + throw new SQLException("not supported"); + } + +} + +class DatabaseX extends SQLite.Database { + + static Object lock = new Object(); + + public DatabaseX() { + super(); + } + + void wait(int ms) { + try { + synchronized (lock) { + lock.wait(ms); + } + } catch (java.lang.Exception e) { + } + } + + public void exec(String sql, SQLite.Callback cb) + throws SQLite.Exception { + super.exec(sql, cb); + synchronized (lock) { + lock.notifyAll(); + } + } + + public void exec(String sql, SQLite.Callback cb, String args[]) + throws SQLite.Exception { + super.exec(sql, cb, args); + synchronized (lock) { + lock.notifyAll(); + } + } + + public SQLite.TableResult get_table(String sql, String args[]) + throws SQLite.Exception { + SQLite.TableResult ret = super.get_table(sql, args); + synchronized (lock) { + lock.notifyAll(); + } + return ret; + } + + public void get_table(String sql, String args[], SQLite.TableResult tbl) + throws SQLite.Exception { + super.get_table(sql, args, tbl); + synchronized (lock) { + lock.notifyAll(); + } + } + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java new file mode 100644 index 0000000..8c14d1d --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java @@ -0,0 +1,1578 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.Hashtable; + +public class JDBCDatabaseMetaData implements DatabaseMetaData { + + private JDBCConnection conn; + + public JDBCDatabaseMetaData(JDBCConnection conn) { + this.conn = conn; + } + + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + public boolean allTablesAreSelectable() throws SQLException { + return true; + } + + public String getURL() throws SQLException { + return conn.url; + } + + public String getUserName() throws SQLException { + return ""; + } + + public boolean isReadOnly() throws SQLException { + return false; + } + + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + public String getDatabaseProductName() throws SQLException { + return "SQLite"; + } + + public String getDatabaseProductVersion() throws SQLException { + return SQLite.Database.version(); + } + + public String getDriverName() throws SQLException { + return "SQLite/JDBC"; + } + + public String getDriverVersion() throws SQLException { + return "" + SQLite.JDBCDriver.MAJORVERSION + "." + + SQLite.JDBCDriver.MINORVERSION; + } + + public int getDriverMajorVersion() { + return SQLite.JDBCDriver.MAJORVERSION; + } + + public int getDriverMinorVersion() { + return SQLite.JDBCDriver.MINORVERSION; + } + + public boolean usesLocalFiles() throws SQLException { + return true; + } + + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + return true; + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return true; + } + + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + public String getSQLKeywords() throws SQLException { + return "SELECT,UPDATE,CREATE,TABLE,VIEW,DELETE,FROM,WHERE" + + ",COMMIT,ROLLBACK,TRIGGER"; + } + + public String getNumericFunctions() throws SQLException { + return ""; + } + + public String getStringFunctions() throws SQLException { + return ""; + } + + public String getSystemFunctions() throws SQLException { + return ""; + } + + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + public String getSearchStringEscape() throws SQLException { + return "\\"; + } + + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + public boolean supportsConvert() throws SQLException { + return false; + } + + public boolean supportsConvert(int fromType, int toType) + throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return true; + } + + public boolean supportsDifferentTableCorrelationNames() + throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return true; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return true; + } + + public boolean supportsGroupBy() throws SQLException { + return true; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return true; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + public boolean supportsNonNullableColumns() throws SQLException { + return true; + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + return true; + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return true; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + public boolean supportsIntegrityEnhancementFacility() + throws SQLException { + return false; + } + + public boolean supportsOuterJoins() throws SQLException { + return false; + } + + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } + + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } + + public String getSchemaTerm() throws SQLException { + return ""; + } + + public String getProcedureTerm() throws SQLException { + return ""; + } + + public String getCatalogTerm() throws SQLException { + return ""; + } + + public boolean isCatalogAtStart() throws SQLException { + return false; + } + + public String getCatalogSeparator() throws SQLException { + return ""; + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInPrivilegeDefinitions() + throws SQLException { + return false; + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInPrivilegeDefinitions() + throws SQLException { + return false; + } + + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public boolean supportsSelectForUpdate() throws SQLException { + return true; + } + + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInExists() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInIns() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + public boolean supportsUnion() throws SQLException { + return false; + } + + public boolean supportsUnionAll() throws SQLException { + return false; + } + + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + public int getMaxConnections() throws SQLException { + return 0; + } + + public int getMaxCursorNameLength() throws SQLException { + return 8; + } + + public int getMaxIndexLength() throws SQLException { + return 0; + } + + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + public int getMaxRowSize() throws SQLException { + return 0; + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return true; + } + + public int getMaxStatementLength() throws SQLException { + return 0; + } + + public int getMaxStatements() throws SQLException { + return 0; + } + + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + public int getDefaultTransactionIsolation() throws SQLException { + return Connection.TRANSACTION_SERIALIZABLE; + } + + public boolean supportsTransactions() throws SQLException { + return true; + } + + public boolean supportsTransactionIsolationLevel(int level) + throws SQLException { + return level == Connection.TRANSACTION_SERIALIZABLE; + } + + public boolean supportsDataDefinitionAndDataManipulationTransactions() + throws SQLException { + return true; + } + + public boolean supportsDataManipulationTransactionsOnly() + throws SQLException { + return false; + } + + public boolean dataDefinitionCausesTransactionCommit() + throws SQLException { + return false; + } + + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + public ResultSet getProcedures(String catalog, String schemaPattern, + String procedureNamePattern) + throws SQLException { + return null; + } + + public ResultSet getProcedureColumns(String catalog, + String schemaPattern, + String procedureNamePattern, + String columnNamePattern) + throws SQLException { + return null; + } + + public ResultSet getTables(String catalog, String schemaPattern, + String tableNamePattern, String types[]) + throws SQLException { + JDBCStatement s = new JDBCStatement(conn); + StringBuffer sb = new StringBuffer(); + sb.append("SELECT '' AS 'TABLE_CAT', " + + "'' AS 'TABLE_SCHEM', " + + "tbl_name AS 'TABLE_NAME', " + + "upper(type) AS 'TABLE_TYPE', " + + "'' AS REMARKS FROM sqlite_master " + + "WHERE tbl_name like "); + if (tableNamePattern != null) { + sb.append(SQLite.Shell.sql_quote(tableNamePattern)); + } else { + sb.append("'%'"); + } + sb.append(" AND "); + if (types == null || types.length == 0) { + sb.append("(type = 'table' or type = 'view')"); + } else { + sb.append("("); + String sep = ""; + for (int i = 0; i < types.length; i++) { + sb.append(sep); + sb.append("type = "); + sb.append(SQLite.Shell.sql_quote(types[i].toLowerCase())); + sep = " or "; + } + sb.append(")"); + } + ResultSet rs = null; + try { + rs = s.executeQuery(sb.toString()); + s.close(); + } catch (SQLException e) { + throw e; + } finally { + s.close(); + } + return rs; + } + + public ResultSet getSchemas() throws SQLException { + String cols[] = { "TABLE_SCHEM" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = { "" }; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getCatalogs() throws SQLException { + String cols[] = { "TABLE_CAT" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = { "" }; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getTableTypes() throws SQLException { + String cols[] = { "TABLE_TYPE" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = new String[1]; + row[0] = "TABLE"; + tr.newrow(row); + row = new String[1]; + row[0] = "VIEW"; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getColumns(String catalog, String schemaPattern, + String tableNamePattern, + String columnNamePattern) + throws SQLException { + JDBCStatement s = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(tableNamePattern) + + ")")); + s.close(); + } catch (SQLException e) { + throw e; + } finally { + s.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_POINTS", + "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT, Types.VARCHAR, + Types.INTEGER, Types.INTEGER, Types.INTEGER, + Types.INTEGER, Types.INTEGER, Types.VARCHAR, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.INTEGER, Types.INTEGER, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h.put(rs0.tr.column[i], new Integer(i)); + } + if (columnNamePattern != null && + columnNamePattern.charAt(0) == '%') { + columnNamePattern = null; + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h.get("name")).intValue(); + if (columnNamePattern != null) { + if (r0[col].compareTo(columnNamePattern) != 0) { + continue; + } + } + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = tableNamePattern; + row[3] = r0[col]; + col = ((Integer) h.get("type")).intValue(); + String typeStr = r0[col]; + int type = mapSqlType(typeStr); + row[4] = "" + type; + row[5] = mapTypeName(type); + row[6] = "" + getD(typeStr, type); + row[7] = "" + getM(typeStr, type); + row[8] = "10"; + row[9] = "0"; + row[11] = null; + col = ((Integer) h.get("dflt_value")).intValue(); + row[12] = r0[col]; + row[13] = "0"; + row[14] = "0"; + row[15] = "65536"; + col = ((Integer) h.get("cid")).intValue(); + Integer cid = new Integer(r0[col]); + row[16] = "" + (cid.intValue() + 1); + col = ((Integer) h.get("notnull")).intValue(); + row[17] = (r0[col].charAt(0) == '0') ? "YES" : "NO"; + row[10] = (r0[col].charAt(0) == '0') ? "" + columnNullable : + "" + columnNoNulls; + tr.newrow(row); + } + } + return rs; + } + + public ResultSet getColumnPrivileges(String catalog, String schema, + String table, + String columnNamePattern) + throws SQLException { + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "GRANTOR", "GRANTEE", + "PRIVILEGE", "IS_GRANTABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getTablePrivileges(String catalog, String schemaPattern, + String tableNamePattern) + throws SQLException { + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "GRANTOR", "GRANTEE", + "PRIVILEGE", "IS_GRANTABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getBestRowIdentifier(String catalog, String schema, + String table, int scope, + boolean nullable) + throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + s1.close(); + } + String cols[] = { + "SCOPE", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "PSEUDO_COLUMN" + }; + int types[] = { + Types.SMALLINT, Types.VARCHAR, Types.SMALLINT, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.SMALLINT, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0 && + rs1 != null && rs1.tr != null && rs1.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + Hashtable<String, Integer> h1 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs1.tr.ncolumns; i++) { + h1.put(rs1.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s2 = new JDBCStatement(conn); + JDBCResultSet rs2 = null; + try { + rs2 = (JDBCResultSet) + (s2.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s2.close(); + } + if (rs2 == null || rs2.tr == null || rs2.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h2 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs2.tr.ncolumns; k++) { + h2.put(rs2.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs2.tr.nrows; k++) { + String r2[] = (String [])(rs2.tr.rows.elementAt(k)); + col = ((Integer) h2.get("name")).intValue(); + String cname = r2[col]; + for (int m = 0; m < rs1.tr.nrows; m++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(m)); + col = ((Integer) h1.get("name")).intValue(); + if (cname.compareTo(r1[col]) == 0) { + String row[] = new String[cols.length]; + row[0] = "" + scope; + row[1] = cname; + row[2] = "" + Types.VARCHAR; + row[3] = "VARCHAR"; + row[4] = "65536"; + row[5] = "0"; + row[6] = "0"; + row[7] = "" + bestRowNotPseudo; + tr.newrow(row); + } + } + } + } + } + if (tr.nrows <= 0) { + String row[] = new String[cols.length]; + row[0] = "" + scope; + row[1] = "_ROWID_"; + row[2] = "" + Types.INTEGER; + row[3] = "INTEGER"; + row[4] = "10"; + row[5] = "0"; + row[6] = "0"; + row[7] = "" + bestRowPseudo; + tr.newrow(row); + } + return rs; + } + + public ResultSet getVersionColumns(String catalog, String schema, + String table) throws SQLException { + String cols[] = { + "SCOPE", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "PSEUDO_COLUMN" + }; + int types[] = { + Types.SMALLINT, Types.VARCHAR, Types.SMALLINT, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.SMALLINT, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getPrimaryKeys(String catalog, String schema, + String table) throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "KEY_SEQ", "PK_NAME" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s1.close(); + } + if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h1 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs1.tr.ncolumns; k++) { + h1.put(rs1.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs1.tr.nrows; k++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(k)); + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + col = ((Integer) h1.get("name")).intValue(); + row[3] = r1[col]; + col = ((Integer) h1.get("seqno")).intValue(); +// BEGIN android-changed + row[4] = "" + (Integer.parseInt(r1[col]) + 1); +// END android-changed + row[5] = iname; + tr.newrow(row); + } + } + } + JDBCStatement s1 = new JDBCStatement(conn); + try { + rs0 = (JDBCResultSet) + (s1.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s1.close(); + } + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("type")).intValue(); + String type = r0[col]; + if (!type.equalsIgnoreCase("integer")) { + continue; + } + col = ((Integer) h0.get("pk")).intValue(); + String pk = r0[col]; + if (pk.charAt(0) == '0') { + continue; + } + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + col = ((Integer) h0.get("name")).intValue(); + row[3] = r0[col]; + col = ((Integer) h0.get("cid")).intValue(); +// BEGIN android-changed + row[4] = "" + (Integer.parseInt(r0[col]) + 1); +// END android-changed + row[5] = ""; + tr.newrow(row); + } + } + return rs; + } + + private void internalImportedKeys(String table, String pktable, + JDBCResultSet in, TableResultX out) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < in.tr.ncolumns; i++) { + h0.put(in.tr.column[i], new Integer(i)); + } + for (int i = 0; i < in.tr.nrows; i++) { + String r0[] = (String [])(in.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("table")).intValue(); + String pktab = r0[col]; + if (pktable != null && !pktable.equalsIgnoreCase(pktab)) { + continue; + } + col = ((Integer) h0.get("from")).intValue(); + String pkcol = r0[col]; + col = ((Integer) h0.get("to")).intValue(); + String fkcol = r0[col]; + col = ((Integer) h0.get("seq")).intValue(); + String seq = r0[col]; + String row[] = new String[out.ncolumns]; + row[0] = ""; + row[1] = ""; + row[2] = pktab; + row[3] = pkcol; + row[4] = ""; + row[5] = ""; + row[6] = table; + row[7] = fkcol == null ? pkcol : fkcol; +// BEGIN android-changed + row[8] = "" + ((Integer.parseInt(seq)) + 1); +// END android-changed + row[9] = + "" + java.sql.DatabaseMetaData.importedKeyNoAction; + row[10] = + "" + java.sql.DatabaseMetaData.importedKeyNoAction; + row[11] = null; + row[12] = null; + row[13] = + "" + java.sql.DatabaseMetaData.importedKeyNotDeferrable; + out.newrow(row); + } + } + + public ResultSet getImportedKeys(String catalog, String schema, + String table) throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA foreign_key_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + internalImportedKeys(table, null, rs0, tr); + } + return rs; + } + + public ResultSet getExportedKeys(String catalog, String schema, + String table) throws SQLException { + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return rs; + } + + public ResultSet getCrossReference(String primaryCatalog, + String primarySchema, + String primaryTable, + String foreignCatalog, + String foreignSchema, + String foreignTable) + throws SQLException { + JDBCResultSet rs0 = null; + if (foreignTable != null && foreignTable.charAt(0) != '%') { + JDBCStatement s0 = new JDBCStatement(conn); + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA foreign_key_list(" + + SQLite.Shell.sql_quote(foreignTable) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + } + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + String pktable = null; + if (primaryTable != null && primaryTable.charAt(0) != '%') { + pktable = primaryTable; + } + internalImportedKeys(foreignTable, pktable, rs0, tr); + } + return rs; + } + + public ResultSet getTypeInfo() throws SQLException { + String cols[] = { + "TYPE_NAME", "DATA_TYPE", "PRECISION", + "LITERAL_PREFIX", "LITERAL_SUFFIX", "CREATE_PARAMS", + "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", + "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", + "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX" + }; + int types[] = { + Types.VARCHAR, Types.SMALLINT, Types.INTEGER, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.SMALLINT, Types.BIT, Types.SMALLINT, + Types.BIT, Types.BIT, Types.BIT, + Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, + Types.INTEGER, Types.INTEGER, Types.INTEGER + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + String row1[] = { + "VARCHAR", "" + Types.VARCHAR, "65536", + "'", "'", null, + "" + typeNullable, "1", "" + typeSearchable, + "0", "0", "0", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row1); + String row2[] = { + "INTEGER", "" + Types.INTEGER, "32", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row2); + String row3[] = { + "DOUBLE", "" + Types.DOUBLE, "16", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "10" + }; + tr.newrow(row3); + String row4[] = { + "FLOAT", "" + Types.FLOAT, "7", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "10" + }; + tr.newrow(row4); + String row5[] = { + "SMALLINT", "" + Types.SMALLINT, "16", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row5); + String row6[] = { + "BIT", "" + Types.BIT, "1", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row6); + String row7[] = { + "TIMESTAMP", "" + Types.TIMESTAMP, "30", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row7); + String row8[] = { + "DATE", "" + Types.DATE, "10", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row8); + String row9[] = { + "TIME", "" + Types.TIME, "8", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row9); + String row10[] = { + "BINARY", "" + Types.BINARY, "65536", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row10); + String row11[] = { + "VARBINARY", "" + Types.VARBINARY, "65536", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row11); + return rs; + } + + public ResultSet getIndexInfo(String catalog, String schema, String table, + boolean unique, boolean approximate) + throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", + "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", + "ASC_OR_DESC", "CARDINALITY", "PAGES", + "FILTER_CONDITION" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.BIT, Types.VARCHAR, Types.VARCHAR, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (unique && uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s1.close(); + } + if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h1 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs1.tr.ncolumns; k++) { + h1.put(rs1.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs1.tr.nrows; k++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(k)); + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + row[3] = (uniq.charAt(0) != '0' || + (iname.charAt(0) == '(' && + iname.indexOf(" autoindex ") > 0)) ? "0" : "1"; + row[4] = ""; + row[5] = iname; + row[6] = "" + tableIndexOther; + col = ((Integer) h1.get("seqno")).intValue(); +// BEGIN android-changed + row[7] = "" + (Integer.parseInt(r1[col]) + 1); +// END android-changed + col = ((Integer) h1.get("name")).intValue(); + row[8] = r1[col]; + row[9] = "A"; + row[10] = "0"; + row[11] = "0"; + row[12] = null; + tr.newrow(row); + } + } + } + return rs; + } + + public boolean supportsResultSetType(int type) throws SQLException { + return type == ResultSet.CONCUR_READ_ONLY; + } + + public boolean supportsResultSetConcurrency(int type, int concurrency) + throws SQLException { + return false; + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, + String typeNamePattern, int[] types) + throws SQLException { + return null; + } + + public Connection getConnection() throws SQLException { + return conn; + } + + static String mapTypeName(int type) { + switch (type) { + case Types.INTEGER: return "integer"; + case Types.SMALLINT: return "smallint"; + case Types.FLOAT: return "float"; + case Types.DOUBLE: return "double"; + case Types.TIMESTAMP: return "timestamp"; + case Types.DATE: return "date"; + case Types.TIME: return "time"; + case Types.BINARY: return "binary"; + case Types.VARBINARY: return "varbinary"; + } + return "varchar"; + } + + static int mapSqlType(String type) { + if (type == null) { + return Types.VARCHAR; + } + type = type.toLowerCase(); + if (type.startsWith("inter")) { + return Types.VARCHAR; + } + if (type.startsWith("numeric") || + type.startsWith("int")) { + return Types.INTEGER; + } + if (type.startsWith("tinyint") || + type.startsWith("smallint")) { + return Types.SMALLINT; + } + if (type.startsWith("float")) { + return Types.FLOAT; + } + if (type.startsWith("double")) { + return Types.DOUBLE; + } + if (type.startsWith("datetime") || + type.startsWith("timestamp")) { + return Types.TIMESTAMP; + } + if (type.startsWith("date")) { + return Types.DATE; + } + if (type.startsWith("time")) { + return Types.TIME; + } + if (type.startsWith("blob")) { + return Types.BINARY; + } + if (type.startsWith("binary")) { + return Types.BINARY; + } + if (type.startsWith("varbinary")) { + return Types.VARBINARY; + } + return Types.VARCHAR; + } + + static int getM(String typeStr, int type) { + int m = 65536; + switch (type) { + case Types.INTEGER: m = 11; break; + case Types.SMALLINT: m = 6; break; + case Types.FLOAT: m = 25; break; + case Types.DOUBLE: m = 54; break; + case Types.TIMESTAMP: return 30; + case Types.DATE: return 10; + case Types.TIME: return 8; + } + typeStr = typeStr.toLowerCase(); + int i1 = typeStr.indexOf('('); + if (i1 > 0) { + ++i1; + int i2 = typeStr.indexOf(',', i1); + if (i2 < 0) { + i2 = typeStr.indexOf(')', i1); + } + if (i2 - i1 > 0) { + String num = typeStr.substring(i1, i2); + try { + m = java.lang.Integer.parseInt(num, 10); + } catch (NumberFormatException e) { + } + } + } + return m; + } + + static int getD(String typeStr, int type) { + int d = 0; + switch (type) { + case Types.INTEGER: d = 10; break; + case Types.SMALLINT: d = 5; break; + case Types.FLOAT: d = 24; break; + case Types.DOUBLE: d = 53; break; + default: return getM(typeStr, type); + } + typeStr = typeStr.toLowerCase(); + int i1 = typeStr.indexOf('('); + if (i1 > 0) { + ++i1; + int i2 = typeStr.indexOf(',', i1); + if (i2 < 0) { + return getM(typeStr, type); + } + i1 = i2; + i2 = typeStr.indexOf(')', i1); + if (i2 - i1 > 0) { + String num = typeStr.substring(i1, i2); + try { + d = java.lang.Integer.parseInt(num, 10); + } catch (NumberFormatException e) { + } + } + } + return d; + } + + public boolean supportsSavepoints() { + return false; + } + + public boolean supportsNamedParameters() { + return false; + } + + public boolean supportsMultipleOpenResults() { + return false; + } + + public boolean supportsGetGeneratedKeys() { + return false; + } + + public boolean supportsResultSetHoldability(int x) { + return false; + } + + public boolean supportsStatementPooling() { + return false; + } + + public boolean locatorsUpdateCopy() throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, + String typeNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, + String tableNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, + String typeNamePattern, + String attributeNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public int getResultSetHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + + public int getDatabaseMajorVersion() { + return SQLite.JDBCDriver.MAJORVERSION; + } + + public int getDatabaseMinorVersion() { + return SQLite.JDBCDriver.MINORVERSION; + } + + public int getJDBCMajorVersion() { + return 1; + } + + public int getJDBCMinorVersion() { + return 0; + } + + public int getSQLStateType() throws SQLException { + return sqlStateXOpen; + } + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java new file mode 100644 index 0000000..ab81867 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java @@ -0,0 +1,752 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.math.BigDecimal; +import java.util.*; + +class BatchArg { + String arg; + boolean blob; + + BatchArg(String arg, boolean blob) { + if (arg == null) { + this.arg = null; + } else { + this.arg = new String(arg); + } + this.blob = blob; + } +} + +public class JDBCPreparedStatement extends JDBCStatement + implements java.sql.PreparedStatement { + + private String sql; + private String args[]; + private boolean blobs[]; + private ArrayList<BatchArg> batch; + private static final boolean nullrepl = + SQLite.Database.version().compareTo("2.5.0") < 0; + + public JDBCPreparedStatement(JDBCConnection conn, String sql) { + super(conn); + this.args = null; + this.blobs = null; + this.batch = null; + this.sql = fixup(sql); + } + + private String fixup(String sql) { + StringBuffer sb = new StringBuffer(); + boolean inq = false; + int nparm = 0; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '\'') { + if (inq) { + char nextChar = 0; + if(i + 1 < sql.length()) { + nextChar = sql.charAt(i + 1); + } + if (nextChar == '\'') { + sb.append(c); + sb.append(nextChar); + i++; + } else { + inq = false; + sb.append(c); + } + } else { + inq = true; + sb.append(c); + } + } else if (c == '?') { + if (inq) { + sb.append(c); + } else { + ++nparm; + sb.append(nullrepl ? "'%q'" : "%Q"); + } + } else if (c == ';') { + if (!inq) { + break; + } + sb.append(c); + } else if (c == '%') { + sb.append("%%"); + } else { + sb.append(c); + } + } + args = new String[nparm]; + blobs = new boolean[nparm]; + try { + clearParameters(); + } catch (SQLException e) { + } + return sb.toString(); + } + + private String fixup2(String sql) { + if (!conn.db.is3()) { + return sql; + } + StringBuffer sb = new StringBuffer(); + int parm = -1; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '%') { + sb.append(c); + ++i; + c = sql.charAt(i); + if (c == 'Q') { + parm++; + if (blobs[parm]) { + c = 's'; + } + } + } + sb.append(c); + } + return sb.toString(); + } + + public ResultSet executeQuery() throws SQLException { + return executeQuery(fixup2(sql), args, false); + } + + public int executeUpdate() throws SQLException { + executeQuery(fixup2(sql), args, true); + return updcnt; + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = nullrepl ? "" : null; + blobs[parameterIndex - 1] = false; + } + + public void setBoolean(int parameterIndex, boolean x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = x ? "1" : "0"; + blobs[parameterIndex - 1] = false; + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setShort(int parameterIndex, short x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setInt(int parameterIndex, int x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setLong(int parameterIndex, long x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = "" + x; + } + blobs[parameterIndex - 1] = false; + } + + public void setString(int parameterIndex, String x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x; + } + blobs[parameterIndex - 1] = false; + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + blobs[parameterIndex - 1] = false; + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (conn.db.is3()) { + args[parameterIndex - 1] = SQLite.StringEncoder.encodeX(x); + blobs[parameterIndex - 1] = true; + } else { + args[parameterIndex - 1] = SQLite.StringEncoder.encode(x); + } + } + } + + public void setDate(int parameterIndex, java.sql.Date x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setTime(int parameterIndex, java.sql.Time x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setTimestamp(int parameterIndex, java.sql.Timestamp x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setAsciiStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public void setUnicodeStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void setBinaryStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void clearParameters() throws SQLException { + for (int i = 0; i < args.length; i++) { + args[i] = nullrepl ? "" : null; + blobs[i] = false; + } + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, + int scale) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public boolean execute() throws SQLException { + return executeQuery(fixup2(sql), args, false) != null; + } + + public void addBatch() throws SQLException { + if (batch == null) { + batch = new ArrayList<BatchArg>(args.length); + } + for (int i = 0; i < args.length; i++) { + batch.add(new BatchArg(args[i], blobs[i])); + } + } + + public int[] executeBatch() throws SQLException { + if (batch == null) { + return new int[0]; + } + int[] ret = new int[batch.size() / args.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = EXECUTE_FAILED; + } + int errs = 0; + int index = 0; + for (int i = 0; i < ret.length; i++) { + for (int k = 0; k < args.length; k++) { + BatchArg b = (BatchArg) batch.get(index++); + + args[i] = b.arg; + blobs[i] = b.blob; + } + try { + ret[i] = executeUpdate(); + } catch (SQLException e) { + ++errs; + } + } + if (errs > 0) { + throw new BatchUpdateException("batch failed", ret); + } + return ret; + } + + public void clearBatch() throws SQLException { + if (batch != null) { + batch.clear(); + batch = null; + } + } + + public void setCharacterStream(int parameterIndex, + java.io.Reader reader, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void setRef(int i, Ref x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setBlob(int i, Blob x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setClob(int i, Clob x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setArray(int i, Array x) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return rs.getMetaData(); + } + + public void setDate(int parameterIndex, java.sql.Date x, Calendar cal) + throws SQLException { + setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, java.sql.Time x, Calendar cal) + throws SQLException { + setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, java.sql.Timestamp x, + Calendar cal) throws SQLException { + setTimestamp(parameterIndex, x); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) + throws SQLException { + setNull(parameterIndex, sqlType); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType, + int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType, + String typeName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.net.URL getURL(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void setURL(int parameterIndex, java.net.URL url) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setNull(String parameterName, int sqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBoolean(String parameterName, boolean val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setByte(String parameterName, byte val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setShort(String parameterName, short val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setInt(String parameterName, int val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setLong(String parameterName, long val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setFloat(String parameterName, float val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDouble(String parameterName, double val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBigDecimal(String parameterName, BigDecimal val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setString(String parameterName, String val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBytes(String parameterName, byte val[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDate(String parameterName, java.sql.Date val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTime(String parameterName, java.sql.Time val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTimestamp(String parameterName, java.sql.Timestamp val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setAsciiStream(String parameterName, + java.io.InputStream s, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBinaryStream(String parameterName, + java.io.InputStream s, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val, int targetSqlType, + int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val, int targetSqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setCharacterStream(String parameterName, + java.io.Reader r, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDate(String parameterName, java.sql.Date val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTime(String parameterName, java.sql.Time val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTimestamp(String parameterName, java.sql.Timestamp val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setNull(String parameterName, int sqlType, String typeName) + throws SQLException { + throw new SQLException("not supported"); + } + + public String getString(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getBoolean(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public short getShort(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public int getInt(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public long getLong(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public float getFloat(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public double getDouble(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte[] getBytes(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(String parameterName) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String parameterName, Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(int parameterIndex, Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Ref getRef(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Ref getRef(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Blob getBlob(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Blob getBlob(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Clob getClob(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Clob getClob(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Array getArray(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Array getArray(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.net.URL getURL(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSet.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSet.java new file mode 100644 index 0000000..06384eb --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSet.java @@ -0,0 +1,932 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.math.BigDecimal; + +public class JDBCResultSet implements java.sql.ResultSet { + + /** + * Current row to be retrieved. + */ + private int row; + + /** + * Table returned by Database.get_table() + */ + protected SQLite.TableResult tr; + + /** + * Statement from which result set was produced. + */ + private JDBCStatement s; + + /** + * Meta data for result set or null. + */ + private JDBCResultSetMetaData m; + + /** + * Last result cell retrieved or null. + */ + private String lastg; + + + public JDBCResultSet(SQLite.TableResult tr, JDBCStatement s) { + this.tr = tr; + this.s = s; + this.m = null; + this.lastg = null; + this.row = -1; + } + + public boolean next() throws SQLException { + if (tr == null) { + return false; + } + row++; + return row < tr.nrows; + } + + public int findColumn(String columnName) throws SQLException { + JDBCResultSetMetaData m = (JDBCResultSetMetaData) getMetaData(); + return m.findColByName(columnName); + } + + public int getRow() throws SQLException { + if (tr == null) { + throw new SQLException("no rows"); + } + return row + 1; + } + + public boolean previous() throws SQLException { + if (tr == null) { + return false; + } + if (row >= 0) { + row--; + } + return row >= 0; + } + + public boolean absolute(int row) throws SQLException { + if (tr == null) { + return false; + } + if (row < 0) { + row = tr.nrows + 1 + row; + } + row--; + if (row < 0 || row > tr.nrows) { + return false; + } + this.row = row; + return true; + } + + public boolean relative(int row) throws SQLException { + if (tr == null) { + return false; + } + if (this.row + row < 0 || this.row + row >= tr.nrows) { + return false; + } + this.row += row; + return true; + } + + public void setFetchDirection(int dir) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchDirection() throws SQLException { + throw new SQLException("not supported"); + } + + public void setFetchSize(int fsize) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchSize() throws SQLException { + throw new SQLException("not supported"); + } + + public String getString(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + return lastg; + } + + public String getString(String columnName) throws SQLException { + int col = findColumn(columnName); + return getString(col); + } + + public int getInt(int columnIndex) throws SQLException { + Integer i = internalGetInt(columnIndex); + if (i != null) { + return i.intValue(); + } + return 0; + } + + private Integer internalGetInt(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Integer.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public int getInt(String columnName) throws SQLException { + int col = findColumn(columnName); + return getInt(col); + } + + public boolean getBoolean(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getBoolean(String columnName) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSetMetaData getMetaData() throws SQLException { + if (m == null) { + m = new JDBCResultSetMetaData(this); + } + return m; + } + + public short getShort(int columnIndex) throws SQLException { + Short s = internalGetShort(columnIndex); + if (s != null) { + return s.shortValue(); + } + return 0; + } + + private Short internalGetShort(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Short.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public short getShort(String columnName) throws SQLException { + int col = findColumn(columnName); + return getShort(col); + } + + public java.sql.Time getTime(int columnIndex) throws SQLException { + return internalGetTime(columnIndex, null); + } + + private java.sql.Time internalGetTime(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Time.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Time getTime(String columnName) throws SQLException { + int col = findColumn(columnName); + return getTime(col); + } + + public java.sql.Time getTime(int columnIndex, java.util.Calendar cal) + throws SQLException { + return internalGetTime(columnIndex, cal); + } + + public java.sql.Time getTime(String columnName, java.util.Calendar cal) + throws SQLException{ + int col = findColumn(columnName); + return getTime(col, cal); + } + + public java.sql.Timestamp getTimestamp(int columnIndex) + throws SQLException{ + return internalGetTimestamp(columnIndex, null); + } + + private java.sql.Timestamp internalGetTimestamp(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Timestamp.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Timestamp getTimestamp(String columnName) + throws SQLException{ + int col = findColumn(columnName); + return getTimestamp(col); + } + + public java.sql.Timestamp getTimestamp(int columnIndex, + java.util.Calendar cal) + throws SQLException { + return internalGetTimestamp(columnIndex, cal); + } + + public java.sql.Timestamp getTimestamp(String columnName, + java.util.Calendar cal) + throws SQLException { + int col = findColumn(columnName); + return getTimestamp(col, cal); + } + + public java.sql.Date getDate(int columnIndex) throws SQLException { + return internalGetDate(columnIndex, null); + } + + private java.sql.Date internalGetDate(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Date.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Date getDate(String columnName) throws SQLException { + int col = findColumn(columnName); + return getDate(col); + } + + public java.sql.Date getDate(int columnIndex, java.util.Calendar cal) + throws SQLException{ + return internalGetDate(columnIndex, cal); + } + + public java.sql.Date getDate(String columnName, java.util.Calendar cal) + throws SQLException{ + int col = findColumn(columnName); + return getDate(col, cal); + } + + public double getDouble(int columnIndex) throws SQLException { + Double d = internalGetDouble(columnIndex); + if (d != null) { + return d.doubleValue(); + } + return 0; + } + + private Double internalGetDouble(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Double.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public double getDouble(String columnName) throws SQLException { + int col = findColumn(columnName); + return getDouble(col); + } + + public float getFloat(int columnIndex) throws SQLException { + Float f = internalGetFloat(columnIndex); + if (f != null) { + return f.floatValue(); + } + return 0; + } + + private Float internalGetFloat(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Float.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public float getFloat(String columnName) throws SQLException { + int col = findColumn(columnName); + return getFloat(col); + } + + public long getLong(int columnIndex) throws SQLException { + Long l = internalGetLong(columnIndex); + if (l != null) { + return l.longValue(); + } + return 0; + } + + private Long internalGetLong(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Long.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public long getLong(String columnName) throws SQLException { + int col = findColumn(columnName); + return getLong(col); + } + + @Deprecated + public java.io.InputStream getUnicodeStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public java.io.InputStream getUnicodeStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getAsciiStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getAsciiStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public BigDecimal getBigDecimal(String columnName, int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public BigDecimal getBigDecimal(int columnIndex, int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getBinaryStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getBinaryStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(String columnName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte[] getBytes(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + byte ret[] = null; + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + if (lastg != null) { + ret = SQLite.StringEncoder.decode(lastg); + } + return ret; + } + + public byte[] getBytes(String columnName) throws SQLException { + int col = findColumn(columnName); + return getBytes(col); + } + + public String getCursorName() throws SQLException { + return null; + } + + public Object getObject(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + Object ret = lastg; + if (tr instanceof TableResultX) { + switch (((TableResultX) tr).sql_type[columnIndex - 1]) { + case Types.SMALLINT: + ret = internalGetShort(columnIndex); + break; + case Types.INTEGER: + ret = internalGetInt(columnIndex); + break; + case Types.DOUBLE: + ret = internalGetDouble(columnIndex); + break; + case Types.FLOAT: + ret = internalGetFloat(columnIndex); + break; + case Types.BIGINT: + ret = internalGetLong(columnIndex); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + ret = getBytes(columnIndex); + break; + case Types.NULL: + ret = null; + break; + /* defaults to String below */ + } + } + return ret; + } + + public Object getObject(String columnName) throws SQLException { + int col = findColumn(columnName); + return getObject(col); + } + + public Object getObject(int columnIndex, java.util.Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String columnIndex, java.util.Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Ref getRef(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Ref getRef(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Blob getBlob(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Blob getBlob(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Clob getClob(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Clob getClob(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Array getArray(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Array getArray(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.Reader getCharacterStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.Reader getCharacterStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public SQLWarning getWarnings() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean wasNull() throws SQLException { + return lastg == null; + } + + public void clearWarnings() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean isFirst() throws SQLException { + if (tr == null) { + return true; + } + return row == 0; + } + + public boolean isBeforeFirst() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + return row < 0; + } + + public void beforeFirst() throws SQLException { + if (tr == null) { + return; + } + row = -1; + } + + public boolean first() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + row = 0; + return true; + } + + public boolean isAfterLast() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + return row >= tr.nrows; + } + + public void afterLast() throws SQLException { + if (tr == null) { + return; + } + row = tr.nrows; + } + + public boolean isLast() throws SQLException { + if (tr == null) { + return true; + } + return row == tr.nrows - 1; + } + + public boolean last() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + row = tr.nrows -1; + return true; + } + + public int getType() throws SQLException { + return TYPE_SCROLL_INSENSITIVE; + } + + public int getConcurrency() throws SQLException { + return CONCUR_READ_ONLY; + } + + public boolean rowUpdated() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean rowInserted() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean rowDeleted() throws SQLException { + throw new SQLException("not supported"); + } + + public void insertRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void updateRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void deleteRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void refreshRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void cancelRowUpdates() throws SQLException { + throw new SQLException("not supported"); + } + + public void moveToInsertRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void moveToCurrentRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void updateNull(int colIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBoolean(int colIndex, boolean b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateByte(int colIndex, byte b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateShort(int colIndex, short b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateInt(int colIndex, int b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateLong(int colIndex, long b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateFloat(int colIndex, float f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDouble(int colIndex, double f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBigDecimal(int colIndex, BigDecimal f) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateString(int colIndex, String s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBytes(int colIndex, byte[] s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDate(int colIndex, java.sql.Date d) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTime(int colIndex, java.sql.Time t) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTimestamp(int colIndex, java.sql.Timestamp t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateAsciiStream(int colIndex, java.io.InputStream in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBinaryStream(int colIndex, java.io.InputStream in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateCharacterStream(int colIndex, java.io.Reader in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(int colIndex, Object obj) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(int colIndex, Object obj, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateNull(String colIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBoolean(String colIndex, boolean b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateByte(String colIndex, byte b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateShort(String colIndex, short b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateInt(String colIndex, int b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateLong(String colIndex, long b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateFloat(String colIndex, float f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDouble(String colIndex, double f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBigDecimal(String colIndex, BigDecimal f) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateString(String colIndex, String s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBytes(String colIndex, byte[] s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDate(String colIndex, java.sql.Date d) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTime(String colIndex, java.sql.Time t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTimestamp(String colIndex, java.sql.Timestamp t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateAsciiStream(String colIndex, java.io.InputStream in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBinaryStream(String colIndex, java.io.InputStream in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateCharacterStream(String colIndex, java.io.Reader in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(String colIndex, Object obj) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(String colIndex, Object obj, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public Statement getStatement() throws SQLException { + if (s == null) { + throw new SQLException("stale result set"); + } + return s; + } + + public void close() throws SQLException { + s = null; + tr = null; + lastg = null; + row = -1; + } + + public java.net.URL getURL(int colIndex) throws SQLException { + if (tr == null || colIndex < 1 || colIndex > tr.ncolumns) { + throw new SQLException("column " + colIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[colIndex - 1]; + java.net.URL url = null; + if (lastg == null) { + return url; + } + try { + url = new java.net.URL(lastg); + } catch (java.lang.Exception e) { + url = null; + } + return url; + } + + public java.net.URL getURL(String colIndex) throws SQLException { + int col = findColumn(colIndex); + return getURL(col); + } + + public void updateRef(int colIndex, java.sql.Ref x) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateRef(String colIndex, java.sql.Ref x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBlob(int colIndex, java.sql.Blob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBlob(String colIndex, java.sql.Blob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateClob(int colIndex, java.sql.Clob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateClob(String colIndex, java.sql.Clob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateArray(int colIndex, java.sql.Array x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateArray(String colIndex, java.sql.Array x) + throws SQLException { + throw new SQLException("not supported"); + } + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java new file mode 100644 index 0000000..934ca78 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java @@ -0,0 +1,212 @@ +package SQLite.JDBC2y; + +import java.sql.*; + +public class JDBCResultSetMetaData implements java.sql.ResultSetMetaData { + + private JDBCResultSet r; + + public JDBCResultSetMetaData(JDBCResultSet r) { + this.r = r; + } + + public String getCatalogName(int column) throws java.sql.SQLException { + return null; + } + + public String getColumnClassName(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return null; + } + if (r.tr instanceof TableResultX) { + switch (((TableResultX) r.tr).sql_type[column]) { + case Types.SMALLINT: return "java.lang.Short"; + case Types.INTEGER: return "java.lang.Integer"; + case Types.DOUBLE: return "java.lang.Double"; + case Types.FLOAT: return "java.lang.Float"; + case Types.BIGINT: return "java.lang.Long"; + case Types.DATE: return "java.sql.Date"; + case Types.TIME: return "java.sql.Time"; + case Types.TIMESTAMP: return "java.sql.Timestamp"; + case Types.BINARY: + case Types.VARBINARY: return "[B"; + /* defaults to varchar below */ + } + } + return "java.lang.String"; + } + return null; + } + + public int getColumnCount() throws java.sql.SQLException { + if (r != null && r.tr != null) { + return r.tr.ncolumns; + } + return 0; + } + + public int getColumnDisplaySize(int column) throws java.sql.SQLException { + return 0; + } + + public String getColumnLabel(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + } + return c; + } + + public String getColumnName(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + if (c != null) { + int i = c.indexOf('.'); + if (i > 0) { + return c.substring(i + 1); + } + } + } + return c; + } + + public int getColumnType(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column >= 0 && column < r.tr.ncolumns) { + if (r.tr instanceof TableResultX) { + return ((TableResultX) r.tr).sql_type[column]; + } + return Types.VARCHAR; + } + } + throw new SQLException("bad column index"); + } + + public String getColumnTypeName(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column >= 0 && column < r.tr.ncolumns) { + if (r.tr instanceof TableResultX) { + switch (((TableResultX) r.tr).sql_type[column]) { + case Types.SMALLINT: return "smallint"; + case Types.INTEGER: return "integer"; + case Types.DOUBLE: return "double"; + case Types.FLOAT: return "float"; + case Types.BIGINT: return "bigint"; + case Types.DATE: return "date"; + case Types.TIME: return "time"; + case Types.TIMESTAMP: return "timestamp"; + case Types.BINARY: return "binary"; + case Types.VARBINARY: return "varbinary"; + /* defaults to varchar below */ + } + } + return "varchar"; + } + } + throw new SQLException("bad column index"); + } + + public int getPrecision(int column) throws java.sql.SQLException { + return 0; + } + + public int getScale(int column) throws java.sql.SQLException { + return 0; + } + + public String getSchemaName(int column) throws java.sql.SQLException { + return null; + } + + public String getTableName(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + if (c != null) { + int i = c.indexOf('.'); + if (i > 0) { + return c.substring(0, i); + } + c = null; + } + } + return c; + } + + public boolean isAutoIncrement(int column) throws java.sql.SQLException { + return false; + } + + public boolean isCaseSensitive(int column) throws java.sql.SQLException { + return false; + } + + public boolean isCurrency(int column) throws java.sql.SQLException { + return false; + } + + public boolean isDefinitelyWritable(int column) + throws java.sql.SQLException { + return true; + } + + public int isNullable(int column) throws java.sql.SQLException { + return columnNullableUnknown; + } + + public boolean isReadOnly(int column) throws java.sql.SQLException { + return false; + } + + public boolean isSearchable(int column) throws java.sql.SQLException { + return true; + } + + public boolean isSigned(int column) throws java.sql.SQLException { + return false; + } + + public boolean isWritable(int column) throws java.sql.SQLException { + return true; + } + + int findColByName(String columnName) throws java.sql.SQLException { + String c = null; + if (r != null && r.tr != null) { + for (int i = 0; i < r.tr.ncolumns; i++) { + c = r.tr.column[i]; + if (c != null) { + if (c.compareToIgnoreCase(columnName) == 0) { + return i + 1; + } + int k = c.indexOf('.'); + if (k > 0) { + c = c.substring(k + 1); + if (c.compareToIgnoreCase(columnName) == 0) { + return i + 1; + } + } + } + c = null; + } + } + throw new SQLException("column " + columnName + " not found"); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCStatement.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCStatement.java new file mode 100644 index 0000000..99d12d3 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCStatement.java @@ -0,0 +1,287 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.*; + +public class JDBCStatement implements java.sql.Statement { + + protected JDBCConnection conn; + protected JDBCResultSet rs; + protected int updcnt; + private ArrayList<String> batch; + + public JDBCStatement(JDBCConnection conn) { + this.conn = conn; + this.updcnt = 0; + this.rs = null; + this.batch = null; + } + + public void setFetchSize(int fetchSize) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchSize() throws SQLException { + return 1; + } + + public int getMaxRows() throws SQLException { + return 0; + } + + public void setMaxRows(int max) throws SQLException { + throw new SQLException("not supported"); + } + + public void setFetchDirection(int fetchDirection) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchDirection() throws SQLException { + return ResultSet.FETCH_UNKNOWN; + } + + public int getResultSetConcurrency() throws SQLException { + return ResultSet.CONCUR_READ_ONLY; + } + + public int getResultSetType() throws SQLException { + return ResultSet.TYPE_SCROLL_INSENSITIVE; + } + + public void setQueryTimeout(int seconds) throws SQLException { + conn.timeout = seconds * 1000; + if (conn.timeout < 0) { + conn.timeout = 120000; + } else if (conn.timeout < 1000) { + conn.timeout = 5000; + } + } + + public int getQueryTimeout() throws SQLException { + return conn.timeout; + } + + public ResultSet getResultSet() throws SQLException { + return rs; + } + + ResultSet executeQuery(String sql, String args[], boolean updonly) + throws SQLException { + SQLite.TableResult tr = null; + if (rs != null) { + rs.close(); + rs = null; + } + updcnt = -1; + if (conn == null || conn.db == null) { + throw new SQLException("stale connection"); + } + int busy = 0; + boolean starttrans = !conn.autocommit && !conn.intrans; + while (true) { + try { + if (starttrans) { + conn.db.exec("BEGIN TRANSACTION", null); + conn.intrans = true; + } + if (args == null) { + if (updonly) { + conn.db.exec(sql, null); + } else { + tr = conn.db.get_table(sql); + } + } else { + if (updonly) { + conn.db.exec(sql, null, args); + } else { + tr = conn.db.get_table(sql, args); + } + } + updcnt = (int) conn.db.changes(); + } catch (SQLite.Exception e) { + if (conn.db.is3() && + conn.db.last_error() == SQLite.Constants.SQLITE_BUSY && + conn.busy3(conn.db, ++busy)) { + try { + if (starttrans && conn.intrans) { + conn.db.exec("ROLLBACK", null); + conn.intrans = false; + } + } catch (SQLite.Exception ee) { + } + try { + int ms = 20 + busy * 10; + if (ms > 1000) { + ms = 1000; + } + synchronized (this) { + this.wait(ms); + } + } catch (java.lang.Exception eee) { + } + continue; + } + throw new SQLException(e.toString()); + } + break; + } + if (!updonly && tr == null) { + throw new SQLException("no result set produced"); + } + if (!updonly && tr != null) { + rs = new JDBCResultSet(new TableResultX(tr), this); + } + return rs; + } + + public ResultSet executeQuery(String sql) throws SQLException { + return executeQuery(sql, null, false); + } + + public boolean execute(String sql) throws SQLException { + return executeQuery(sql) != null; + } + + public void cancel() throws SQLException { + if (conn == null || conn.db == null) { + throw new SQLException("stale connection"); + } + conn.db.interrupt(); + } + + public void clearWarnings() throws SQLException { + } + + public Connection getConnection() throws SQLException { + return conn; + } + + public void addBatch(String sql) throws SQLException { + if (batch == null) { + batch = new ArrayList<String>(1); + } + batch.add(sql); + } + + public int[] executeBatch() throws SQLException { + if (batch == null) { + return new int[0]; + } + int[] ret = new int[batch.size()]; + for (int i = 0; i < ret.length; i++) { + ret[i] = EXECUTE_FAILED; + } + int errs = 0; + for (int i = 0; i < ret.length; i++) { + try { + execute((String) batch.get(i)); + ret[i] = updcnt; + } catch (SQLException e) { + ++errs; + } + } + if (errs > 0) { + throw new BatchUpdateException("batch failed", ret); + } + return ret; + } + + public void clearBatch() throws SQLException { + if (batch != null) { + batch.clear(); + batch = null; + } + } + + public void close() throws SQLException { + clearBatch(); + conn = null; + } + + public int executeUpdate(String sql) throws SQLException { + executeQuery(sql, null, true); + return updcnt; + } + + public int getMaxFieldSize() throws SQLException { + return 0; + } + + public boolean getMoreResults() throws SQLException { + if (rs != null) { + rs.close(); + rs = null; + } + return false; + } + + public int getUpdateCount() throws SQLException { + return updcnt; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public void setCursorName(String name) throws SQLException { + throw new SQLException("not supported"); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + throw new SQLException("not supported"); + } + + public void setMaxFieldSize(int max) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getMoreResults(int x) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getGeneratedKeys() throws SQLException { + throw new SQLException("not supported"); + } + + public int executeUpdate(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return executeUpdate(sql); + } + + public int executeUpdate(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public int executeUpdate(String sql, String colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public boolean execute(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return execute(sql); + } + + public boolean execute(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public boolean execute(String sql, String colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public int getResultSetHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBC2y/TableResultX.java b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/TableResultX.java new file mode 100644 index 0000000..205372f --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBC2y/TableResultX.java @@ -0,0 +1,37 @@ +package SQLite.JDBC2y; + +import java.sql.Types; +import java.util.Vector; + +public class TableResultX extends SQLite.TableResult { + public int sql_type[]; + + public TableResultX() { + super(); + sql_type = new int[this.ncolumns]; + for (int i = 0; i < this.ncolumns; i++) { + sql_type[i] = Types.VARCHAR; + } + } + + public TableResultX(SQLite.TableResult tr) { + this.column = tr.column; + this.rows = tr.rows; + this.ncolumns = tr.ncolumns; + this.nrows = tr.nrows; + this.types = tr.types; + sql_type = new int[tr.ncolumns]; + for (int i = 0; i < this.ncolumns; i++) { + sql_type[i] = Types.VARCHAR; + } + if (tr.types != null) { + for (int i = 0; i < tr.types.length; i++) { + sql_type[i] = JDBCDatabaseMetaData.mapSqlType(tr.types[i]); + } + } + } + + void sql_types(int types[]) { + sql_type = types; + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/JDBCDriver.java b/sqlite-jdbc/src/main/java/SQLite/JDBCDriver.java new file mode 100644 index 0000000..63b95ee --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/JDBCDriver.java @@ -0,0 +1,109 @@ +package SQLite; + +import java.sql.*; +import java.util.Properties; + +public class JDBCDriver implements java.sql.Driver { + + public static final int MAJORVERSION = 1; + public static final int MINORVERSION = 2; + + private static java.lang.reflect.Constructor makeConn = null; + + protected Connection conn; + + static { + try { + Class connClass = null; + Class args[] = new Class[2]; + args[0] = Class.forName("java.lang.String"); + args[1] = args[0]; + String jvers = java.lang.System.getProperty("java.version"); + String cvers; + if (jvers == null || jvers.startsWith("1.0")) { + throw new java.lang.Exception("unsupported java version"); + } else if (jvers.startsWith("1.1")) { + cvers = "SQLite.JDBC1.JDBCConnection"; + } else if (jvers.startsWith("1.2") || jvers.startsWith("1.3")) { + cvers = "SQLite.JDBC2.JDBCConnection"; + } else if (jvers.startsWith("1.4")) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } else if (jvers.startsWith("1.5")) { + cvers = "SQLite.JDBC2y.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception e) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } + } else { + cvers = "SQLite.JDBC2z.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception e) { + cvers = "SQLite.JDBC2y.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception ee) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } + } + } + connClass = Class.forName(cvers); + makeConn = connClass.getConstructor(args); + java.sql.DriverManager.registerDriver(new JDBCDriver()); + } catch (java.lang.Exception e) { + System.err.println(e); + } + } + + public JDBCDriver() { + } + + public boolean acceptsURL(String url) throws SQLException { + return url.startsWith("sqlite:/") || + url.startsWith("jdbc:sqlite:/"); + } + + public Connection connect(String url, Properties info) + throws SQLException { + if (!acceptsURL(url)) { + return null; + } + Object args[] = new Object[2]; + args[0] = url; + if (info != null) { + args[1] = info.getProperty("encoding"); + } + if (args[1] == null) { + args[1] = java.lang.System.getProperty("SQLite.encoding"); + } + try { + conn = (Connection) makeConn.newInstance(args); + } catch (java.lang.reflect.InvocationTargetException ie) { + throw new SQLException(ie.getTargetException().toString()); + } catch (java.lang.Exception e) { + throw new SQLException(e.toString()); + } + return conn; + } + + public int getMajorVersion() { + return MAJORVERSION; + } + + public int getMinorVersion() { + return MINORVERSION; + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) + throws SQLException { + DriverPropertyInfo p[] = new DriverPropertyInfo[1]; + DriverPropertyInfo pp = new DriverPropertyInfo("encoding", ""); + p[0] = pp; + return p; + } + + public boolean jdbcCompliant() { + return false; + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/ProgressHandler.java b/sqlite-jdbc/src/main/java/SQLite/ProgressHandler.java new file mode 100644 index 0000000..b2ec7c0 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/ProgressHandler.java @@ -0,0 +1,17 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined progress handler. + */ + +public interface ProgressHandler { + + /** + * Invoked for N SQLite VM opcodes. + * The method should return true to continue the + * current query, or false in order + * to abandon the action.<BR><BR> + */ + + public boolean progress(); +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Shell.java b/sqlite-jdbc/src/main/java/SQLite/Shell.java new file mode 100644 index 0000000..78d37a1 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Shell.java @@ -0,0 +1,669 @@ +package SQLite; + +import SQLite.*; +import java.io.*; +import java.util.*; + +/** + * SQLite command line shell. This is a partial reimplementaion + * of sqlite/src/shell.c and can be invoked by:<P> + * + * <verb> + * java SQLite.Shell [OPTIONS] database [SHELLCMD] + * or + * java -jar sqlite.jar [OPTIONS] database [SHELLCMD] + * </verb> + */ + +public class Shell implements Callback { + Database db; + boolean echo; + int count; + int mode; + boolean showHeader; + String tableName; + String sep; + String cols[]; + int colwidth[]; + String destTable; + PrintWriter pw; + PrintWriter err; + + static final int MODE_Line = 0; + static final int MODE_Column = 1; + static final int MODE_List = 2; + static final int MODE_Semi = 3; + static final int MODE_Html = 4; + static final int MODE_Insert = 5; + static final int MODE_Insert2 = 6; + + public Shell(PrintWriter pw, PrintWriter err) { + this.pw = pw; + this.err = err; + } + + public Shell(PrintStream ps, PrintStream errs) { + pw = new PrintWriter(ps); + err = new PrintWriter(errs); + } + + protected Object clone() { + Shell s = new Shell(this.pw, this.err); + s.db = db; + s.echo = echo; + s.mode = mode; + s.count = 0; + s.showHeader = showHeader; + s.tableName = tableName; + s.sep = sep; + s.colwidth = colwidth; + return s; + } + + static public String sql_quote_dbl(String str) { + if (str == null) { + return "NULL"; + } + int i, single = 0, dbl = 0; + for (i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\'') { + single++; + } else if (str.charAt(i) == '"') { + dbl++; + } + } + if (dbl == 0) { + return "\"" + str + "\""; + } + StringBuffer sb = new StringBuffer("\""); + for (i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '"') { + sb.append("\"\""); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + static public String sql_quote(String str) { + if (str == null) { + return "NULL"; + } + int i, single = 0, dbl = 0; + for (i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\'') { + single++; + } else if (str.charAt(i) == '"') { + dbl++; + } + } + if (single == 0) { + return "'" + str + "'"; + } + if (dbl == 0) { + return "\"" + str + "\""; + } + StringBuffer sb = new StringBuffer("'"); + for (i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '\'') { + sb.append("''"); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + static String html_quote(String str) { + if (str == null) { + return "NULL"; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '&') { + sb.append("&"); + } else { + int x = c; + if (x < 32 || x > 127) { + sb.append("&#" + x + ";"); + } else { + sb.append(c); + } + } + } + return sb.toString(); + } + + static boolean is_numeric(String str) { + try { + Double d = Double.valueOf(str); + } catch (java.lang.Exception e) { + return false; + } + return true; + } + + void set_table_name(String str) { + if (str == null) { + tableName = ""; + return; + } + tableName = Shell.sql_quote(str); + } + + public void columns(String args[]) { + cols = args; + } + + public void types(String args[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public boolean newrow(String args[]) { + int i; + String tname; + switch (mode) { + case Shell.MODE_Line: + if (args.length == 0) { + break; + } + if (count++ > 0) { + pw.println(""); + } + for (i = 0; i < args.length; i++) { + pw.println(cols[i] + " = " + + args[i] == null ? "NULL" : args[i]); + } + break; + case Shell.MODE_Column: + String csep = ""; + if (count++ == 0) { + colwidth = new int[args.length]; + for (i = 0; i < args.length; i++) { + int w, n; + w = cols[i].length(); + if (w < 10) { + w = 10; + } + colwidth[i] = w; + if (showHeader) { + pw.print(csep + cols[i]); + csep = " "; + } + } + if (showHeader) { + pw.println(""); + } + } + if (args.length == 0) { + break; + } + csep = ""; + for (i = 0; i < args.length; i++) { + pw.print(csep + (args[i] == null ? "NULL" : args[i])); + csep = " "; + } + pw.println(""); + break; + case Shell.MODE_Semi: + case Shell.MODE_List: + if (count++ == 0 && showHeader) { + for (i = 0; i < args.length; i++) { + pw.print(cols[i] + + (i == args.length - 1 ? "\n" : sep)); + } + } + if (args.length == 0) { + break; + } + for (i = 0; i < args.length; i++) { + pw.print(args[i] == null ? "NULL" : args[i]); + if (mode == Shell.MODE_Semi) { + pw.print(";"); + } else if (i < args.length - 1) { + pw.print(sep); + } + } + pw.println(""); + break; + case MODE_Html: + if (count++ == 0 && showHeader) { + pw.print("<TR>"); + for (i = 0; i < args.length; i++) { + pw.print("<TH>" + html_quote(cols[i]) + "</TH>"); + } + pw.println("</TR>"); + } + if (args.length == 0) { + break; + } + pw.print("<TR>"); + for (i = 0; i < args.length; i++) { + pw.print("<TD>" + html_quote(args[i]) + "</TD>"); + } + pw.println("</TR>"); + break; + case MODE_Insert: + if (args.length == 0) { + break; + } + tname = tableName; + if (destTable != null) { + tname = destTable; + } + pw.print("INSERT INTO " + tname + " VALUES("); + for (i = 0; i < args.length; i++) { + String tsep = i > 0 ? "," : ""; + if (args[i] == null) { + pw.print(tsep + "NULL"); + } else if (is_numeric(args[i])) { + pw.print(tsep + args[i]); + } else { + pw.print(tsep + sql_quote(args[i])); + } + } + pw.println(");"); + break; + case MODE_Insert2: + if (args.length == 0) { + break; + } + tname = tableName; + if (destTable != null) { + tname = destTable; + } + pw.print("INSERT INTO " + tname + " VALUES("); + for (i = 0; i < args.length; i++) { + String tsep = i > 0 ? "," : ""; + pw.print(tsep + args[i]); + } + pw.println(");"); + break; + } + return false; + } + + void do_meta(String line) { + StringTokenizer st = new StringTokenizer(line.toLowerCase()); + int n = st.countTokens(); + if (n <= 0) { + return; + } + String cmd = st.nextToken(); + String args[] = new String[n - 1]; + int i = 0; + while (st.hasMoreTokens()) { + args[i] = st.nextToken(); + ++i; + } + if (cmd.compareTo(".dump") == 0) { + new DBDump(this, args); + return; + } + if (cmd.compareTo(".echo") == 0) { + if (args.length > 0 && + (args[0].startsWith("y") || args[0].startsWith("on"))) { + echo = true; + } + return; + } + if (cmd.compareTo(".exit") == 0) { + try { + db.close(); + } catch (Exception e) { + } + System.exit(0); + } + if (cmd.compareTo(".header") == 0) { + if (args.length > 0 && + (args[0].startsWith("y") || args[0].startsWith("on"))) { + showHeader = true; + } + return; + } + if (cmd.compareTo(".help") == 0) { + pw.println(".dump ?TABLE? ... Dump database in text fmt"); + pw.println(".echo ON|OFF Command echo on or off"); + pw.println(".enc ?NAME? Change encoding"); + pw.println(".exit Exit program"); + pw.println(".header ON|OFF Display headers on or off"); + pw.println(".help This message"); + pw.println(".mode MODE Set output mode to\n" + + " line, column, insert\n" + + " list, or html"); + pw.println(".mode insert TABLE Generate SQL insert stmts"); + pw.println(".schema ?PATTERN? List table schema"); + pw.println(".separator STRING Set separator string"); + pw.println(".tables ?PATTERN? List table names"); + return; + } + if (cmd.compareTo(".mode") == 0) { + if (args.length > 0) { + if (args[0].compareTo("line") == 0) { + mode = Shell.MODE_Line; + } else if (args[0].compareTo("column") == 0) { + mode = Shell.MODE_Column; + } else if (args[0].compareTo("list") == 0) { + mode = Shell.MODE_List; + } else if (args[0].compareTo("html") == 0) { + mode = Shell.MODE_Html; + } else if (args[0].compareTo("insert") == 0) { + mode = Shell.MODE_Insert; + if (args.length > 1) { + destTable = args[1]; + } + } + } + return; + } + if (cmd.compareTo(".separator") == 0) { + if (args.length > 0) { + sep = args[0]; + } + return; + } + if (cmd.compareTo(".tables") == 0) { + TableResult t = null; + if (args.length > 0) { + try { + String qarg[] = new String[1]; + qarg[0] = args[0]; + t = db.get_table("SELECT name FROM sqlite_master " + + "WHERE type='table' AND " + + "name LIKE '%%%q%%' " + + "ORDER BY name", qarg); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } else { + try { + t = db.get_table("SELECT name FROM sqlite_master " + + "WHERE type='table' ORDER BY name"); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + if (t != null) { + for (i = 0; i < t.nrows; i++) { + String tab = ((String[]) t.rows.elementAt(i))[0]; + if (tab != null) { + pw.println(tab); + } + } + } + return; + } + if (cmd.compareTo(".schema") == 0) { + if (args.length > 0) { + try { + String qarg[] = new String[1]; + qarg[0] = args[0]; + db.exec("SELECT sql FROM sqlite_master " + + "WHERE type!='meta' AND " + + "name LIKE '%%%q%%' AND " + + "sql NOTNULL " + + "ORDER BY type DESC, name", + this, qarg); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } else { + try { + db.exec("SELECT sql FROM sqlite_master " + + "WHERE type!='meta' AND " + + "sql NOTNULL " + + "ORDER BY tbl_name, type DESC, name", + this); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + return; + } + if (cmd.compareTo(".enc") == 0) { + try { + db.set_encoding(args.length > 0 ? args[0] : null); + } catch (Exception e) { + err.println("" + e); + err.flush(); + } + return; + } + err.println("Unknown command '" + cmd + "'"); + err.flush(); + } + + String read_line(BufferedReader is, String prompt) { + try { + if (prompt != null) { + pw.print(prompt); + pw.flush(); + } + String line = is.readLine(); + return line; + } catch (IOException e) { + return null; + } + } + + void do_input(BufferedReader is) { + String line, sql = null; + String prompt = "SQLITE> "; + while ((line = read_line(is, prompt)) != null) { + if (echo) { + pw.println(line); + } + if (line.length() > 0 && line.charAt(0) == '.') { + do_meta(line); + } else { + if (sql == null) { + sql = line; + } else { + sql = sql + " " + line; + } + if (Database.complete(sql)) { + try { + db.exec(sql, this); + } catch (Exception e) { + if (!echo) { + err.println(sql); + } + err.println("SQL Error: " + e); + err.flush(); + } + sql = null; + prompt = "SQLITE> "; + } else { + prompt = "SQLITE? "; + } + } + pw.flush(); + } + if (sql != null) { + err.println("Incomplete SQL: " + sql); + err.flush(); + } + } + + void do_cmd(String sql) { + if (db == null) { + return; + } + if (sql.length() > 0 && sql.charAt(0) == '.') { + do_meta(sql); + } else { + try { + db.exec(sql, this); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + } + + public static void main(String args[]) { + Shell s = new Shell(System.out, System.err); + s.mode = Shell.MODE_List; + s.sep = "|"; + s.showHeader = false; + s.db = new Database(); + String dbname = null, sql = null; + for (int i = 0; i < args.length; i++) { + if(args[i].compareTo("-html") ==0) { + s.mode = Shell.MODE_Html; + } else if (args[i].compareTo("-list") == 0) { + s.mode = Shell.MODE_List; + } else if (args[i].compareTo("-line") == 0) { + s.mode = Shell.MODE_Line; + } else if (i < args.length - 1 && + args[i].compareTo("-separator") == 0) { + ++i; + s.sep = args[i]; + } else if (args[i].compareTo("-header") == 0) { + s.showHeader = true; + } else if (args[i].compareTo("-noheader") == 0) { + s.showHeader = false; + } else if (args[i].compareTo("-echo") == 0) { + s.echo = true; + } else if (dbname == null) { + dbname = args[i]; + } else if (sql == null) { + sql = args[i]; + } else { + System.err.println("Arguments: ?OPTIONS? FILENAME ?SQL?"); + System.exit(1); + } + } + if (dbname == null) { + System.err.println("No database file given"); + System.exit(1); + } + try { + s.db.open(dbname, 0); + } catch (Exception e) { + System.err.println("Unable to open database: " + e); + System.exit(1); + } + if (sql != null) { + s.do_cmd(sql); + } else { + // BEGIN android-modified + BufferedReader is = + new BufferedReader(new InputStreamReader(System.in), 8192); + // END android-modified + s.do_input(is); + } + try { + s.db.close(); + } catch (Exception ee) { + } + } +} + +/** + * Internal class for dumping an entire database. + * It contains a special callback interface to traverse the + * tables of the current database and output create SQL statements + * and for the data insert SQL statements. + */ + +class DBDump implements Callback { + Shell s; + + DBDump(Shell s, String tables[]) { + this.s = s; + s.pw.println("BEGIN TRANSACTION;"); + if (tables == null || tables.length == 0) { + try { + s.db.exec("SELECT name, type, sql FROM sqlite_master " + + "WHERE type!='meta' AND sql NOT NULL " + + "ORDER BY substr(type,2,1), name", this); + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + } + } else { + String arg[] = new String[1]; + for (int i = 0; i < tables.length; i++) { + arg[0] = tables[i]; + try { + s.db.exec("SELECT name, type, sql FROM sqlite_master " + + "WHERE tbl_name LIKE '%q' AND type!='meta' " + + " AND sql NOT NULL " + + " ORDER BY substr(type,2,1), name", + this, arg); + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + } + } + } + s.pw.println("COMMIT;"); + } + + public void columns(String col[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public void types(String args[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public boolean newrow(String args[]) { + if (args.length != 3) { + return true; + } + s.pw.println(args[2] + ";"); + if (args[1].compareTo("table") == 0) { + Shell s2 = (Shell) s.clone(); + s2.mode = Shell.MODE_Insert; + s2.set_table_name(args[0]); + String qargs[] = new String[1]; + qargs[0] = args[0]; + try { + if (s2.db.is3()) { + TableResult t = null; + t = s2.db.get_table("PRAGMA table_info('%q')", qargs); + String query; + if (t != null) { + StringBuffer sb = new StringBuffer(); + String sep = ""; + + sb.append("SELECT "); + for (int i = 0; i < t.nrows; i++) { + String col = ((String[]) t.rows.elementAt(i))[1]; + sb.append(sep + "quote(" + + Shell.sql_quote_dbl(col) + ")"); + sep = ","; + } + sb.append(" from '%q'"); + query = sb.toString(); + s2.mode = Shell.MODE_Insert2; + } else { + query = "SELECT * from '%q'"; + } + s2.db.exec(query, s2, qargs); + } else { + s2.db.exec("SELECT * from '%q'", s2, qargs); + } + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + return true; + } + } + return false; + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Stmt.java b/sqlite-jdbc/src/main/java/SQLite/Stmt.java new file mode 100644 index 0000000..c4f72ed --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Stmt.java @@ -0,0 +1,288 @@ +package SQLite; + +/** + * Class to represent compiled SQLite3 statement. + * + * Note, that all native methods of this class are + * not synchronized, i.e. it is up to the caller + * to ensure that only one thread is in these + * methods at any one time. + */ + +public class Stmt { + + /** + * Internal handle for the SQLite3 statement. + */ + + private long handle = 0; + + /** + * Internal last error code for prepare()/step() methods. + */ + + protected int error_code = 0; + + /** + * Prepare the next SQL statement for the Stmt instance. + * @return true when the next piece of the SQL statement sequence + * has been prepared, false on end of statement sequence. + */ + + public native boolean prepare() throws SQLite.Exception; + + /** + * Perform one step of compiled SQLite3 statement. + * + * Example:<BR> + * <PRE> + * ... + * try { + * Stmt s = db.prepare("select * from x; select * from y;"); + * s.bind(...); + * ... + * s.bind(...); + * while (s.step(cb)) { + * Object o = s.value(...); + * ... + * } + * // s.reset() for re-execution or + * // s.prepare() for the next piece of SQL + * while (s.prepare()) { + * s.bind(...); + * ... + * s.bind(...); + * while (s.step(cb)) { + * Object o = s.value(...); + * ... + * } + * } + * } catch (SQLite.Exception e) { + * s.close(); + * } + * </PRE> + * + * @return true when row data is available, false on end + * of result set. + */ + + public native boolean step() throws SQLite.Exception; + + /** + * Close the compiled SQLite3 statement. + */ + + public native void close() throws SQLite.Exception; + + /** + * Reset the compiled SQLite3 statement without + * clearing parameter bindings. + */ + + public native void reset() throws SQLite.Exception; + + /** + * Clear all bound parameters of the compiled SQLite3 statement. + */ + + public native void clear_bindings() throws SQLite.Exception; + + /** + * Bind positional integer value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, int value) throws SQLite.Exception; + + /** + * Bind positional long value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, long value) throws SQLite.Exception; + + /** + * Bind positional double value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, double value) throws SQLite.Exception; + + /** + * Bind positional byte array to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter, may be null + */ + + public native void bind(int pos, byte[] value) throws SQLite.Exception; + + /** + * Bind positional String to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter, may be null + */ + + public native void bind(int pos, String value) throws SQLite.Exception; + + /** + * Bind positional SQL null to compiled SQLite3 statement. + * @param pos parameter index, 1-based + */ + + public native void bind(int pos) throws SQLite.Exception; + + /** + * Bind positional zero'ed blob to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param length byte size of zero blob + */ + + public native void bind_zeroblob(int pos, int length) + throws SQLite.Exception; + + /** + * Return number of parameters in compiled SQLite3 statement. + * @return int number of parameters + */ + + public native int bind_parameter_count() throws SQLite.Exception; + + /** + * Return name of parameter in compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @return String parameter name + */ + + public native String bind_parameter_name(int pos) throws SQLite.Exception; + + /** + * Return index of named parameter in compiled SQLite3 statement. + * @param name of parameter + * @return int index of parameter, 1-based + */ + + public native int bind_parameter_index(String name) + throws SQLite.Exception; + + + /** + * Retrieve integer column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return int column value + */ + + public native int column_int(int col) throws SQLite.Exception; + + /** + * Retrieve long column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return long column value + */ + public native long column_long(int col) throws SQLite.Exception; + + /** + * Retrieve double column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return double column value + */ + public native double column_double(int col) throws SQLite.Exception; + + /** + * Retrieve blob column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return byte[] column value + */ + public native byte[] column_bytes(int col) throws SQLite.Exception; + + /** + * Retrieve string column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return String column value + */ + public native String column_string(int col) throws SQLite.Exception; + + /** + * Retrieve column type from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return column type code, e.g. SQLite.Constants.SQLITE_INTEGER + */ + public native int column_type(int col) throws SQLite.Exception; + + /** + * Retrieve number of columns of exec'ed SQLite3 statement. + * @return int number of columns + */ + + public native int column_count() throws SQLite.Exception; + + /** + * Retrieve column data as object from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return Object or null + */ + + public Object column(int col) throws SQLite.Exception { + switch (column_type(col)) { + case Constants.SQLITE_INTEGER: + return new Long(column_long(col)); + case Constants.SQLITE_FLOAT: + return new Double(column_double(col)); + case Constants.SQLITE_BLOB: + return column_bytes(col); + case Constants.SQLITE3_TEXT: + return column_string(col); + } + return null; + } + + /** + * Return table name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_table_name(int col) throws SQLite.Exception; + + /** + * Return database name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_database_name(int col) throws SQLite.Exception; + + /** + * Return declared column type of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_decltype(int col) throws SQLite.Exception; + + /** + * Return origin column name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_origin_name(int col) throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/StringEncoder.java b/sqlite-jdbc/src/main/java/SQLite/StringEncoder.java new file mode 100644 index 0000000..c2f20ad --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/StringEncoder.java @@ -0,0 +1,201 @@ +package SQLite; + +/** + * String encoder/decoder for SQLite. + * + * This module was kindly donated by Eric van der Maarel of Nedap N.V. + * + * This encoder was implemented based on an original idea from an anonymous + * author in the source code of the SQLite distribution. + * I feel obliged to provide a quote from the original C-source code: + * + * "The author disclaims copyright to this source code. In place of + * a legal notice, here is a blessing: + * + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give." + * + */ + +public class StringEncoder { + + /** + * Encodes the given byte array into a string that can be used by + * the SQLite database. The database cannot handle null (0x00) and + * the character '\'' (0x27). The encoding consists of escaping + * these characters with a reserved character (0x01). The escaping + * is applied after determining and applying a shift that minimizes + * the number of escapes required. + * With this encoding the data of original size n is increased to a + * maximum of 1+(n*257)/254. + * For sufficiently large n the overhead is thus less than 1.2%. + * @param a the byte array to be encoded. A null reference is handled as + * an empty array. + * @return the encoded bytes as a string. When an empty array is + * provided a string of length 1 is returned, the value of + * which is bogus. + * When decoded with this class' <code>decode</code> method + * a string of size 1 will return an empty byte array. + */ + + public static String encode(byte[] a) { + // check input + if (a == null || a.length == 0) { + // bogus shift, no data + return "x"; + } + // determine count + int[] cnt = new int[256]; + for (int i = 0 ; i < a.length; i++) { + cnt[a[i] & 0xff]++; + } + // determine shift for minimum number of escapes + int shift = 1; + int nEscapes = a.length; + for (int i = 1; i < 256; i++) { + if (i == '\'') { + continue; + } + int sum = cnt[i] + cnt[(i + 1) & 0xff] + cnt[(i + '\'') & 0xff]; + if (sum < nEscapes) { + nEscapes = sum; + shift = i; + if (nEscapes == 0) { + // cannot become smaller + break; + } + } + } + // construct encoded output + int outLen = a.length + nEscapes + 1; + StringBuffer out = new StringBuffer(outLen); + out.append((char)shift); + for (int i = 0; i < a.length; i++) { + // apply shift + char c = (char)((a[i] - shift)&0xff); + // insert escapes + if (c == 0) { // forbidden + out.append((char)1); + out.append((char)1); + } else if (c == 1) { // escape character + out.append((char)1); + out.append((char)2); + } else if (c == '\'') { // forbidden + out.append((char)1); + out.append((char)3); + } else { + out.append(c); + } + } + return out.toString(); + } + + /** + * Decodes the given string that is assumed to be a valid encoding + * of a byte array. Typically the given string is generated by + * this class' <code>encode</code> method. + * @param s the given string encoding. + * @return the byte array obtained from the decoding. + * @throws IllegalArgumentException when the string given is not + * a valid encoded string for this encoder. + */ + + public static byte[] decode(String s) { + char[] a = s.toCharArray(); + if (a.length > 2 && a[0] == 'X' && + a[1] == '\'' && a[a.length-1] == '\'') { + // SQLite3 BLOB syntax + byte[] result = new byte[(a.length-3)/2]; + for (int i = 2, k = 0; i < a.length - 1; i += 2, k++) { + byte tmp = (byte) (a[i] - '0'); + if (tmp > 15) { + tmp -= 0x20; + } + result[k] = (byte) (tmp << 4); + tmp = (byte) (a[i+1] - '0'); + if (tmp > 15) { + tmp -= 0x20; + } + result[k] |= tmp; + } + return result; + } + // first element is the shift + byte[] result = new byte[a.length-1]; + int i = 0; + int shift = s.charAt(i++); + int j = 0; + while (i < s.length()) { + int c; + if ((c = s.charAt(i++)) == 1) { // escape character found + if ((c = s.charAt(i++)) == 1) { + c = 0; + } else if (c == 2) { + c = 1; + } else if (c == 3) { + c = '\''; + } else { + throw new IllegalArgumentException( + "invalid string passed to decoder: " + j); + } + } + // do shift + result[j++] = (byte)((c + shift) & 0xff); + } + int outLen = j; + // provide array of correct length + if (result.length != outLen) { + result = byteCopy(result, 0, outLen, new byte[outLen]); + } + return result; + } + + /** + * Copies count elements from source, starting at element with + * index offset, to the given target. + * @param source the source. + * @param offset the offset. + * @param count the number of elements to be copied. + * @param target the target to be returned. + * @return the target being copied to. + */ + + private static byte[] byteCopy(byte[] source, int offset, + int count, byte[] target) { + for (int i = offset, j = 0; i < offset + count; i++, j++) { + target[j] = source[i]; + } + return target; + } + + + static final char[] xdigits = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + /** + * Encodes the given byte array into SQLite3 blob notation, ie X'..' + * @param a the byte array to be encoded. A null reference is handled as + * an empty array. + * @return the encoded bytes as a string. + */ + + public static String encodeX(byte[] a) { + // check input + if (a == null || a.length == 0) { + return "X''"; + } + int outLen = a.length + 3; + StringBuffer out = new StringBuffer(outLen); + out.append('X'); + out.append('\''); + for (int i = 0; i < a.length; i++) { + out.append(xdigits[a[i] >> 4]); + out.append(xdigits[a[i] & 0x0F]); + } + out.append('\''); + return out.toString(); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/TableResult.java b/sqlite-jdbc/src/main/java/SQLite/TableResult.java new file mode 100644 index 0000000..1a7fb57 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/TableResult.java @@ -0,0 +1,133 @@ +package SQLite; + +import java.util.Vector; + +/** + * Class representing an SQLite result set as + * returned by the + * <A HREF="Database.html#get_table(java.lang.String)">Database.get_table</A> + * convenience method. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * ... + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * System.out.print(db.get_table("select * from TEST")); + * ... + * </PRE> + * Example output:<BR> + * + * <PRE> + * id|firstname|lastname| + * 0|John|Doe| + * 1|Speedy|Gonzales| + * ... + * </PRE> + */ + +public class TableResult implements Callback { + + /** + * Number of columns in the result set. + */ + + public int ncolumns; + + /** + * Number of rows in the result set. + */ + + public int nrows; + + /** + * Column names of the result set. + */ + + public String column[]; + + /** + * Types of columns of the result set or null. + */ + + public String types[]; + + /** + * Rows of the result set. Each row is stored as a String array. + */ + + public Vector rows; + + /** + * Create an empty result set. + */ + + public TableResult() { + clear(); + } + + /** + * Clear result set. + */ + + public void clear() { + column = new String[0]; + types = null; + rows = new Vector(); + ncolumns = nrows = 0; + } + + /** + * Callback method used while the query is executed. + */ + + public void columns(String coldata[]) { + column = coldata; + ncolumns = column.length; + } + + /** + * Callback method used while the query is executed. + */ + + public void types(String types[]) { + this.types = types; + } + + /** + * Callback method used while the query is executed. + */ + + public boolean newrow(String rowdata[]) { + if (rowdata != null) { + rows.addElement(rowdata); + nrows++; + } + return false; + } + + /** + * Make String representation of result set. + */ + + public String toString() { + StringBuffer sb = new StringBuffer(); + int i; + for (i = 0; i < ncolumns; i++) { + sb.append(column[i] == null ? "NULL" : column[i]); + sb.append('|'); + } + sb.append('\n'); + for (i = 0; i < nrows; i++) { + int k; + String row[] = (String[]) rows.elementAt(i); + for (k = 0; k < ncolumns; k++) { + sb.append(row[k] == null ? "NULL" : row[k]); + sb.append('|'); + } + sb.append('\n'); + } + return sb.toString(); + } +} diff --git a/sqlite-jdbc/src/main/java/SQLite/Trace.java b/sqlite-jdbc/src/main/java/SQLite/Trace.java new file mode 100644 index 0000000..19ed2a1 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Trace.java @@ -0,0 +1,17 @@ +package SQLite; + +/** + * Callback interface for SQLite's trace function. + */ + +public interface Trace { + + /** + * Callback to trace (ie log) one SQL statement. + * + * @param stmt SQL statement string + */ + + public void trace(String stmt); +} + diff --git a/sqlite-jdbc/src/main/java/SQLite/Vm.java b/sqlite-jdbc/src/main/java/SQLite/Vm.java new file mode 100644 index 0000000..9856ed0 --- /dev/null +++ b/sqlite-jdbc/src/main/java/SQLite/Vm.java @@ -0,0 +1,78 @@ +package SQLite; + +/** + * Class to represent compiled SQLite VM. + */ + +public class Vm { + + /** + * Internal handle for the compiled SQLite VM. + */ + + private long handle = 0; + + /** + * Internal last error code for compile()/step() methods. + */ + + protected int error_code = 0; + + /** + * Perform one step on compiled SQLite VM. + * The result row is passed to the given callback interface.<BR><BR> + * + * Example:<BR> + * <PRE> + * ... + * try { + * Vm vm = db.compile("select * from x; select * from y;"); + * while (vm.step(cb)) { + * ... + * } + * while (vm.compile()) { + * while (vm.step(cb)) { + * ... + * } + * } + * } catch (SQLite.Exception e) { + * } + * </PRE> + * + * @param cb the object implementing the callback methods. + * @return true as long as more row data can be retrieved, + * false, otherwise. + */ + + public native boolean step(Callback cb) throws SQLite.Exception; + + /** + * Compile the next SQL statement for the SQLite VM instance. + * @return true when SQL statement has been compiled, false + * on end of statement sequence. + */ + + public native boolean compile() throws SQLite.Exception; + + /** + * Abort the compiled SQLite VM. + */ + + public native void stop() throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sqlite-jdbc/src/main/native/sqlite_jni.c b/sqlite-jdbc/src/main/native/sqlite_jni.c new file mode 100644 index 0000000..1333d24 --- /dev/null +++ b/sqlite-jdbc/src/main/native/sqlite_jni.c @@ -0,0 +1,4404 @@ +#include "JNIHelp.h" +#include "sqlite_jni_defs.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#if HAVE_SQLITE2 +#include "sqlite.h" +#endif + +#if HAVE_SQLITE3 +#include "sqlite3.h" +#undef HAVE_SQLITE_COMPILE +#define HAVE_SQLITE_COMPILE 1 +#undef HAVE_SQLITE_PROGRESS_HANDLER +#define HAVE_SQLITE_PROGRESS_HANDLER 1 +#undef HAVE_SQLITE_TRACE +#define HAVE_SQLITE_TRACE 1 +#if !HAVE_SQLITE3_MALLOC +#define sqlite3_malloc malloc +#define sqlite3_free free +#endif +#if !HAVE_SQLITE3_BIND_PARAMETER_COUNT +#define sqlite3_bind_parameter_count(dummy) (1000) +#endif +#endif + +#if HAVE_SQLITE2 && HAVE_SQLITE3 +#define HAVE_BOTH_SQLITE 1 +#endif + +#define CANT_PASS_VALIST_AS_CHARPTR + +#include "sqlite_jni.h" + +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) +#define MAX_PARAMS 256 +#else +#define MAX_PARAMS 32 +#endif + +/* free memory proc */ + +typedef void (freemem)(void *); + +/* internal handle for SQLite database */ + +typedef struct { + void *sqlite; /* SQLite handle */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + int ver; /* version code */ + jobject bh; /* BusyHandler object */ + jobject cb; /* Callback object */ + jobject ai; /* Authorizer object */ + jobject tr; /* Trace object */ + jobject ph; /* ProgressHandler object */ + JNIEnv *env; /* Java environment for callbacks */ + int row1; /* true while processing first row */ + int haveutf; /* true for SQLite UTF-8 support */ + jstring enc; /* encoding or 0 */ + struct hfunc *funcs; /* SQLite user defined function handles */ +#if HAVE_SQLITE_COMPILE + struct hvm *vms; /* Compiled SQLite VMs */ +#endif +#if HAVE_SQLITE3 + sqlite3_stmt *stmt; /* For callback() */ +#endif +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + struct hbl *blobs; /* SQLite3 blob handles */ +#endif +} handle; + +/* internal handle for SQLite user defined function */ + +typedef struct hfunc { + struct hfunc *next; /* next function */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + jobject fc; /* FunctionContext object */ + jobject fi; /* Function object */ + jobject db; /* Database object */ + handle *h; /* SQLite database handle */ + void *sf; /* SQLite function handle */ + JNIEnv *env; /* Java environment for callbacks */ +} hfunc; + +#if HAVE_SQLITE_COMPILE +/* internal handle for SQLite VM (sqlite_compile()) */ + +typedef struct hvm { + struct hvm *next; /* next vm handle */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + void *vm; /* SQLite 2/3 VM/statement */ + char *tail; /* tail SQL string */ + int tail_len; /* only for SQLite3/prepare */ + handle *h; /* SQLite database handle */ + handle hh; /* fake SQLite database handle */ +} hvm; +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +/* internal handle for sqlite3_blob */ + +typedef struct hbl { + struct hbl *next; /* next blob handle */ + sqlite3_blob *blob; /* SQLite3 blob */ + handle *h; /* SQLite database handle */ +} hbl; +#endif + +/* ISO to/from UTF-8 translation */ + +typedef struct { + char *result; /* translated C string result */ + char *tofree; /* memory to be free'd, or 0 */ + jstring jstr; /* resulting Java string or 0 */ +} transstr; + +/* static cached weak class refs, field and method ids */ + +static jclass C_java_lang_String = 0; + +static jfieldID F_SQLite_Database_handle = 0; +static jfieldID F_SQLite_Database_error_code = 0; +static jfieldID F_SQLite_FunctionContext_handle = 0; +static jfieldID F_SQLite_Vm_handle = 0; +static jfieldID F_SQLite_Vm_error_code = 0; +static jfieldID F_SQLite_Stmt_handle = 0; +static jfieldID F_SQLite_Stmt_error_code = 0; +static jfieldID F_SQLite_Blob_handle = 0; +static jfieldID F_SQLite_Blob_size = 0; + +static jmethodID M_java_lang_String_getBytes = 0; +static jmethodID M_java_lang_String_getBytes2 = 0; +static jmethodID M_java_lang_String_initBytes = 0; +static jmethodID M_java_lang_String_initBytes2 = 0; + +static const char xdigits[] = "0123456789ABCDEF"; + +static void +seterr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Database_error_code, v.i); +} + +#if HAVE_SQLITE_COMPILE +static void +setvmerr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Vm_error_code, v.i); +} + +#if HAVE_SQLITE3 +static void +setstmterr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Stmt_error_code, v.i); +} + +static int +jstrlen(const jchar *jstr) +{ + int len = 0; + + if (jstr) { + while (*jstr++) { + len++; + } + } + return len; +} +#endif +#endif + +static void * +gethandle(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Database_handle); + return (void *) v.l; +} + +#if HAVE_SQLITE_COMPILE +static void * +gethvm(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Vm_handle); + return (void *) v.l; +} + +#if HAVE_SQLITE3 +static void * +gethstmt(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Stmt_handle); + return (void *) v.l; +} +#endif +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void * +gethbl(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Blob_handle); + return (void *) v.l; +} +#endif + +static void +delglobrefp(JNIEnv *env, jobject *obj) +{ + if (*obj) { + (*env)->DeleteGlobalRef(env, *obj); + *obj = 0; + } +} + +static jobject +globrefpop(JNIEnv *env, jobject *obj) +{ + jobject ret = 0; + + if (*obj) { + ret = *obj; + *obj = 0; + } + return ret; +} + +static void +globrefset(JNIEnv *env, jobject obj, jobject *ref) +{ + if (ref) { + if (obj) { + *ref = (*env)->NewGlobalRef(env, obj); + } else { + *ref = 0; + } + } +} + +static void +freep(char **strp) +{ + if (strp && *strp) { + free(*strp); + *strp = 0; + } +} + +static void +throwex(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "SQLite/Exception"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} + +static void +throwoom(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} + +static void +throwclosed(JNIEnv *env) +{ + throwex(env, "database already closed"); +} + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void +throwioex(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "java/io/IOException"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} +#endif + +static void +transfree(transstr *dest) +{ + dest->result = 0; + freep(&dest->tofree); +} + +static char * +trans2iso(JNIEnv *env, int haveutf, jstring enc, jstring src, + transstr *dest) +{ + jbyteArray bytes = 0; + jthrowable exc; + + dest->result = 0; + dest->tofree = 0; + if (haveutf) { + const jsize utfLength = (*env)->GetStringUTFLength(env, src); + dest->result = dest->tofree = malloc(utfLength + 1); + if (!dest->tofree) { + throwoom(env, "string translation failed"); + return dest->result; + } + (*env)->GetStringUTFRegion(env, src, 0, utfLength, dest->result); + return dest->result; + } + if (enc) { + bytes = (*env)->CallObjectMethod(env, src, + M_java_lang_String_getBytes2, enc); + } else { + bytes = (*env)->CallObjectMethod(env, src, + M_java_lang_String_getBytes); + } + exc = (*env)->ExceptionOccurred(env); + if (!exc) { + jint len = (*env)->GetArrayLength(env, bytes); + dest->tofree = malloc(len + 1); + if (!dest->tofree) { + throwoom(env, "string translation failed"); + return dest->result; + } + dest->result = dest->tofree; + (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *) dest->result); + dest->result[len] = '\0'; + } else { + (*env)->DeleteLocalRef(env, exc); + } + return dest->result; +} + +static jstring +trans2utf(JNIEnv *env, int haveutf, jstring enc, const char *src, + transstr *dest) +{ + jbyteArray bytes = 0; + int len; + + dest->result = 0; + dest->tofree = 0; + dest->jstr = 0; + if (!src) { + return dest->jstr; + } + if (haveutf) { + dest->jstr = (*env)->NewStringUTF(env, src); + return dest->jstr; + } + len = strlen(src); + bytes = (*env)->NewByteArray(env, len); + if (bytes) { + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) src); + if (enc) { + dest->jstr = + (*env)->NewObject(env, C_java_lang_String, + M_java_lang_String_initBytes2, bytes, enc); + } else { + dest->jstr = + (*env)->NewObject(env, C_java_lang_String, + M_java_lang_String_initBytes, bytes); + } + (*env)->DeleteLocalRef(env, bytes); + return dest->jstr; + } + throwoom(env, "string translation failed"); + return dest->jstr; +} + +#if HAVE_SQLITE2 +static int +busyhandler(void *udata, const char *table, int count) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->bh) { + transstr tabstr; + jclass cls = (*env)->GetObjectClass(env, h->bh); + jmethodID mid = (*env)->GetMethodID(env, cls, "busy", + "(Ljava/lang/String;I)Z"); + + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return ret; + } + trans2utf(env, h->haveutf, h->enc, table, &tabstr); + ret = (*env)->CallBooleanMethod(env, h->bh, mid, tabstr.jstr, + (jint) count) + != JNI_FALSE; + (*env)->DeleteLocalRef(env, tabstr.jstr); + (*env)->DeleteLocalRef(env, cls); + } + return ret; +} +#endif + +#if HAVE_SQLITE3 +static int +busyhandler3(void *udata, int count) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->bh) { + jclass cls = (*env)->GetObjectClass(env, h->bh); + jmethodID mid = (*env)->GetMethodID(env, cls, "busy", + "(Ljava/lang/String;I)Z"); + + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return ret; + } + ret = (*env)->CallBooleanMethod(env, h->bh, mid, 0, (jint) count) + != JNI_FALSE; + (*env)->DeleteLocalRef(env, cls); + } + return ret; +} +#endif + +static int +progresshandler(void *udata) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->ph) { + jclass cls = (*env)->GetObjectClass(env, h->ph); + jmethodID mid = (*env)->GetMethodID(env, cls, "progress", "()Z"); + + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return ret; + } + ret = (*env)->CallBooleanMethod(env, h->ph, mid) != JNI_TRUE; + (*env)->DeleteLocalRef(env, cls); + } + return ret; +} + +static int +callback(void *udata, int ncol, char **data, char **cols) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + + if (env && h->cb) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->cb); + jmethodID mid; + jobjectArray arr = 0; + jint i; + + if (h->row1) { + mid = (*env)->GetMethodID(env, cls, "columns", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i]) { + transstr col; + + trans2utf(env, h->haveutf, h->enc, cols[i], &col); + (*env)->SetObjectArrayElement(env, arr, i, col.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, col.jstr); + } + } + h->row1 = 0; + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } +#if HAVE_BOTH_SQLITE + if (h->is3) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid && h->stmt) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + const char *ctype = + sqlite3_column_decltype(h->stmt, i); + + if (!ctype) { + switch (sqlite3_column_type(h->stmt, i)) { + case SQLITE_INTEGER: ctype = "integer"; break; + case SQLITE_FLOAT: ctype = "double"; break; + default: +#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT) + case SQLITE_TEXT: +#else +#ifdef SQLITE3_TEXT + case SQLITE3_TEXT: +#endif +#endif + ctype = "text"; break; + case SQLITE_BLOB: ctype = "blob"; break; + case SQLITE_NULL: ctype = "null"; break; + } + } + if (ctype) { + transstr ty; + + trans2utf(env, 1, 0, ctype, &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } else { + if (h->ver >= 0x020506 && cols[ncol]) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i + ncol]) { + transstr ty; + + trans2utf(env, h->haveutf, h->enc, + cols[i + ncol], &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } + } +#else +#if HAVE_SQLITE2 + if (h->ver >= 0x020506 && cols[ncol]) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i + ncol]) { + transstr ty; + + trans2utf(env, h->haveutf, h->enc, + cols[i + ncol], &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } +#endif +#if HAVE_SQLITE3 + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid && h->stmt) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + const char *ctype = sqlite3_column_decltype(h->stmt, i); + + if (!ctype) { + switch (sqlite3_column_type(h->stmt, i)) { + case SQLITE_INTEGER: ctype = "integer"; break; + case SQLITE_FLOAT: ctype = "double"; break; + default: +#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT) + case SQLITE_TEXT: +#else +#ifdef SQLITE3_TEXT + case SQLITE3_TEXT: +#endif +#endif + ctype = "text"; break; + case SQLITE_BLOB: ctype = "blob"; break; + case SQLITE_NULL: ctype = "null"; break; + } + } + if (ctype) { + transstr ty; + + trans2utf(env, 1, 0, ctype, &ty); + (*env)->SetObjectArrayElement(env, arr, i, ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } +#endif +#endif + } + mid = (*env)->GetMethodID(env, cls, "newrow", + "([Ljava/lang/String;)Z"); + if (mid) { + jboolean rc; + + if (data) { + arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0); + } else { + arr = 0; + } + for (i = 0; arr && i < ncol; i++) { + if (data[i]) { + transstr dats; + + trans2utf(env, h->haveutf, h->enc, data[i], &dats); + (*env)->SetObjectArrayElement(env, arr, i, dats.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, dats.jstr); + } + } + rc = (*env)->CallBooleanMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + if (arr) { + (*env)->DeleteLocalRef(env, arr); + } + (*env)->DeleteLocalRef(env, cls); + return rc != JNI_FALSE; + } + } + return 0; +} + +static void +doclose(JNIEnv *env, jobject obj, int final) +{ + handle *h = gethandle(env, obj); + + if (h) { + hfunc *f; +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl; +#endif +#if HAVE_SQLITE_COMPILE + hvm *v; + + while ((v = h->vms)) { + h->vms = v->next; + v->next = 0; + v->h = 0; + if (v->vm) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + } +#endif + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + } else { + sqlite_close((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + h->sqlite = 0; + } + while ((f = h->funcs)) { + h->funcs = f->next; + f->h = 0; + f->sf = 0; + f->env = 0; + if (f->fc) { + (*env)->SetLongField(env, f->fc, + F_SQLite_FunctionContext_handle, 0); + } + delglobrefp(env, &f->db); + delglobrefp(env, &f->fi); + delglobrefp(env, &f->fc); + free(f); + } +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + while ((bl = h->blobs)) { + h->blobs = bl->next; + bl->next = 0; + bl->h = 0; + if (bl->blob) { + sqlite3_blob_close(bl->blob); + } + bl->blob = 0; + } +#endif + delglobrefp(env, &h->bh); + delglobrefp(env, &h->cb); + delglobrefp(env, &h->ai); + delglobrefp(env, &h->tr); + delglobrefp(env, &h->ph); + delglobrefp(env, &h->enc); + free(h); + (*env)->SetLongField(env, obj, F_SQLite_Database_handle, 0); + return; + } + if (!final) { + throwclosed(env); + } +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1close(JNIEnv *env, jobject obj) +{ + doclose(env, obj, 0); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1finalize(JNIEnv *env, jobject obj) +{ + doclose(env, obj, 1); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1busy_1timeout(JNIEnv *env, jobject obj, jint ms) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms); + } else { + sqlite_busy_timeout((sqlite *) h->sqlite, ms); + } +#else +#if HAVE_SQLITE2 + sqlite_busy_timeout((sqlite *) h->sqlite, ms); +#endif +#if HAVE_SQLITE3 + sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_version(JNIEnv *env, jclass cls) +{ + /* CHECK THIS */ +#if HAVE_BOTH_SQLITE + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else + return (*env)->NewStringUTF(env, sqlite3_libversion()); +#endif +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_dbversion(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (*env)->NewStringUTF(env, sqlite3_libversion()); + } else { + return (*env)->NewStringUTF(env, sqlite_libversion()); + } +#else +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else + return (*env)->NewStringUTF(env, sqlite3_libversion()); +#endif +#endif + } + return (*env)->NewStringUTF(env, "unknown"); +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Database__1last_1insert_1rowid(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite); + } else { + return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite); +#endif +#endif + } + throwclosed(env); + return (jlong) 0; +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Database__1changes(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (jlong) sqlite3_changes((sqlite3 *) h->sqlite); + } else { + return (jlong) sqlite_changes((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + return (jlong) sqlite_changes((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + return (jlong) sqlite3_changes((sqlite3 *) h->sqlite); +#endif +#endif + } + throwclosed(env); + return (jlong) 0; +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Database__1complete(JNIEnv *env, jclass cls, jstring sql) +{ + transstr sqlstr; + jboolean result; + + if (!sql) { + return JNI_FALSE; + } +#if HAVE_BOTH_SQLITE || HAVE_SQLITE3 + /* CHECK THIS */ + trans2iso(env, 1, 0, sql, &sqlstr); + result = sqlite3_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE; +#else + trans2iso(env, strcmp(sqlite_libencoding(), "UTF-8") == 0, 0, + sql, &sqlstr); + result = sqlite_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE; +#endif + transfree(&sqlstr); + return result; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1interrupt(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_interrupt((sqlite3 *) h->sqlite); + } else { + sqlite_interrupt((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_interrupt((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_interrupt((sqlite3 *) h->sqlite); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open(JNIEnv *env, jobject obj, jstring file, jint mode) +{ + handle *h = gethandle(env, obj); + jthrowable exc; + char *err = 0; + transstr filename; + int maj, min, lev; + + if (h) { + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + } else { + sqlite_close((sqlite *) h->sqlite); + } + h->is3 = 0; +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + h->sqlite = 0; + } + } else { + h = malloc(sizeof (handle)); + if (!h) { + throwoom(env, "unable to get SQLite handle"); + return; + } + h->sqlite = 0; + h->bh = h->cb = h->ai = h->tr = h->ph = 0; + /* CHECK THIS */ +#if HAVE_BOTH_SQLITE + h->is3 = 0; + h->stmt = 0; + h->haveutf = 1; +#else +#if HAVE_SQLITE2 + h->haveutf = strcmp(sqlite_libencoding(), "UTF-8") == 0; +#endif +#if HAVE_SQLITE3 + h->stmt = 0; + h->haveutf = 1; +#endif +#endif + h->enc = 0; + h->funcs = 0; + h->ver = 0; +#if HAVE_SQLITE_COMPILE + h->vms = 0; +#endif +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + h->blobs = 0; +#endif + } + h->env = 0; + if (!file) { + throwex(env, err ? err : "invalid file name"); + return; + } + trans2iso(env, h->haveutf, h->enc, file, &filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + { + FILE *f = fopen(filename.result, "rb"); + int c_0 = EOF; + + if (f) { + c_0 = fgetc(f); + fclose(f); + } + if (c_0 != '*') { + int rc = sqlite3_open(filename.result, (sqlite3 **) &h->sqlite); + + if (rc == SQLITE_OK) { + h->is3 = 1; + } else if (h->sqlite) { + sqlite3_close((sqlite3 *) h->sqlite); + h->sqlite = 0; + } + } else { + h->sqlite = (void *) sqlite_open(filename.result, + (int) mode, &err); + } + } +#else +#if HAVE_SQLITE2 + h->sqlite = (void *) sqlite_open(filename.result, (int) mode, &err); +#endif +#if HAVE_SQLITE3 + if (sqlite3_open(filename.result, (sqlite3 **) &h->sqlite) != SQLITE_OK) { + if (h->sqlite) { + sqlite3_close((sqlite3 *) h->sqlite); + h->sqlite = 0; + } + } +#endif +#endif + transfree(&filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + h->is3 = 0; + } else { + sqlite_close((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + } + h->sqlite = 0; + return; + } + if (h->sqlite) { + jvalue v; + + v.j = 0; + v.l = (jobject) h; + (*env)->SetLongField(env, obj, F_SQLite_Database_handle, v.j); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif +#if HAVE_BOTH_SQLITE + if (h->is3) { + sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev); + } else { + sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev); + } +#else +#if HAVE_SQLITE2 + sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev); +#endif +#if HAVE_SQLITE3 + sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev); +#endif +#endif + h->ver = ((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (lev & 0xFF); + return; + } + throwex(env, err ? err : "unknown error in open"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open_1aux_1file(JNIEnv *env, jobject obj, jstring file) +{ + handle *h = gethandle(env, obj); +#if HAVE_SQLITE_OPEN_AUX_FILE + jboolean b; + jthrowable exc; + char *err = 0; + transstr filename; + int ret; +#endif + + if (h && h->sqlite) { +#if HAVE_SQLITE_OPEN_AUX_FILE +#if HAVE_BOTH_SQLITE + if (h->is3) { + throwex(env, "unsupported"); + } +#endif + trans2iso(env, h->haveutf, h->enc, file, &filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite_open_aux_file((sqlite *) h->sqlite, + filename.result, &err); + transfree(&filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err) { + sqlite_freemem(err); + } + return; + } + if (ret != SQLITE_OK) { + throwex(env, err ? err : sqlite_error_string(ret)); + } + if (err) { + sqlite_freemem(err); + } +#else + throwex(env, "unsupported"); +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1busy_1handler(JNIEnv *env, jobject obj, jobject bh) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->bh); + globrefset(env, bh, &h->bh); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h); + } else { + sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h); + } +#else +#if HAVE_SQLITE2 + sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h); +#endif +#if HAVE_SQLITE3 + sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2 + (JNIEnv *env, jobject obj, jstring sql, jobject cb) +{ + handle *h = gethandle(env, obj); + freemem *freeproc; + + if (!sql) { + throwex(env, "invalid SQL statement"); + return; + } + if (h) { + if (h->sqlite) { + jthrowable exc; + int rc; + char *err = 0; + transstr sqlstr; + jobject oldcb = globrefpop(env, &h->cb); + + globrefset(env, cb, &h->cb); + h->env = env; + h->row1 = 1; + trans2iso(env, h->haveutf, h->enc, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + if (h->is3) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite3_free; + } else { + rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite_freemem; + } +#else +#if HAVE_SQLITE2 + rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite_freemem; +#endif +#if HAVE_SQLITE3 + rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite3_free; +#endif +#endif + transfree(&sqlstr); + exc = (*env)->ExceptionOccurred(env); + delglobrefp(env, &h->cb); + h->cb = oldcb; + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err) { + freeproc(err); + } + return; + } + if (rc != SQLITE_OK) { + char msg[128]; + + seterr(env, obj, rc); + if (!err) { + sprintf(msg, "error %d in sqlite*_exec", rc); + } + throwex(env, err ? err : msg); + } + if (err) { + freeproc(err); + } + return; + } + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2 + (JNIEnv *env, jobject obj, jstring sql, jobject cb, jobjectArray args) +{ + handle *h = gethandle(env, obj); + freemem *freeproc = 0; + + if (!sql) { + throwex(env, "invalid SQL statement"); + return; + } + if (h) { + if (h->sqlite) { + jthrowable exc; + int rc = SQLITE_ERROR, nargs, i; + char *err = 0, *p; + const char *str = (*env)->GetStringUTFChars(env, sql, NULL); + transstr sqlstr; + struct args { + char *arg; + jobject obj; + transstr trans; + } *argv = 0; + char **cargv = 0; + jobject oldcb = globrefpop(env, &h->cb); + + globrefset(env, cb, &h->cb); + p = (char *) str; + nargs = 0; + while (*p) { + if (*p == '%') { + ++p; + if (*p == 'q' || *p == 's') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "too much SQL parameters"); + return; + } + } else if (h->ver >= 0x020500 && *p == 'Q') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "too much SQL parameters"); + return; + } + } else if (*p != '%') { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "bad % specification in query"); + return; + } + } + ++p; + } + cargv = malloc((sizeof (*argv) + sizeof (char *)) + * MAX_PARAMS); + if (!cargv) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwoom(env, "unable to allocate arg vector"); + return; + } + argv = (struct args *) (cargv + MAX_PARAMS); + for (i = 0; i < MAX_PARAMS; i++) { + cargv[i] = 0; + argv[i].arg = 0; + argv[i].obj = 0; + argv[i].trans.result = argv[i].trans.tofree = 0; + } + exc = 0; + for (i = 0; i < nargs; i++) { + jobject so = (*env)->GetObjectArrayElement(env, args, i); + + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + break; + } + if (so) { + argv[i].obj = so; + argv[i].arg = cargv[i] = + trans2iso(env, h->haveutf, h->enc, argv[i].obj, + &argv[i].trans); + } + } + if (exc) { + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + return; + } + h->env = env; + h->row1 = 1; + trans2iso(env, h->haveutf, h->enc, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (!exc) { +#if HAVE_BOTH_SQLITE + if (h->is3) { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + + if (s) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback, + h, &err); + sqlite3_free(s); + } else { + rc = SQLITE_NOMEM; + } + freeproc = (freemem *) sqlite3_free; + } else { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + rc = sqlite_exec_vprintf((sqlite *) h->sqlite, + sqlstr.result, callback, h, &err, + (char *) cargv); +#else + rc = sqlite_exec_printf((sqlite *) h->sqlite, + sqlstr.result, callback, + h, &err, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + freeproc = (freemem *) sqlite_freemem; + } +#else +#if HAVE_SQLITE2 +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + rc = sqlite_exec_vprintf((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err, (char *) cargv); +#else + rc = sqlite_exec_printf((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + freeproc = (freemem *) sqlite_freemem; +#endif +#if HAVE_SQLITE3 +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + + if (s) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback, + h, &err); + sqlite3_free(s); + } else { + rc = SQLITE_NOMEM; + } + freeproc = (freemem *) sqlite3_free; +#endif +#endif + exc = (*env)->ExceptionOccurred(env); + } + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + freep((char **) &cargv); + delglobrefp(env, &h->cb); + h->cb = oldcb; + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err && freeproc) { + freeproc(err); + } + return; + } + if (rc != SQLITE_OK) { + char msg[128]; + + seterr(env, obj, rc); + if (!err) { + sprintf(msg, "error %d in sqlite*_exec", rc); + } + throwex(env, err ? err : msg); + } + if (err && freeproc) { + freeproc(err); + } + return; + } + } + throwclosed(env); +} + +static hfunc * +getfunc(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_FunctionContext_handle); + return (hfunc *) v.l; +} + +#if HAVE_SQLITE2 +static void +call_common(sqlite_func *sf, int isstep, int nargs, const char **args) +{ + hfunc *f = (hfunc *) sqlite_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = + (*env)->GetMethodID(env, cls, + isstep ? "step" : "function", + "(LSQLite/FunctionContext;[Ljava/lang/String;)V"); + jobjectArray arr; + int i; + + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return; + } + arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0); + for (i = 0; i < nargs; i++) { + if (args[i]) { + transstr arg; + jthrowable exc; + + trans2utf(env, f->h->haveutf, f->h->enc, args[i], &arg); + (*env)->SetObjectArrayElement(env, arr, i, arg.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + (*env)->DeleteLocalRef(env, arg.jstr); + } + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr); + (*env)->DeleteLocalRef(env, arr); + (*env)->DeleteLocalRef(env, cls); + } +} + +static void +call_func(sqlite_func *sf, int nargs, const char **args) +{ + call_common(sf, 0, nargs, args); +} + +static void +call_step(sqlite_func *sf, int nargs, const char **args) +{ + call_common(sf, 1, nargs, args); +} + +static void +call_final(sqlite_func *sf) +{ + hfunc *f = (hfunc *) sqlite_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = (*env)->GetMethodID(env, cls, "last_step", + "(LSQLite/FunctionContext;)V"); + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return; + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc); + (*env)->DeleteLocalRef(env, cls); + } +} +#endif + +#if HAVE_SQLITE3 +static void +call3_common(sqlite3_context *sf, int isstep, int nargs, sqlite3_value **args) +{ + hfunc *f = (hfunc *) sqlite3_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = + (*env)->GetMethodID(env, cls, + isstep ? "step" : "function", + "(LSQLite/FunctionContext;[Ljava/lang/String;)V"); + jobjectArray arr; + int i; + + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return; + } + arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0); + for (i = 0; i < nargs; i++) { + if (args[i]) { + transstr arg; + jthrowable exc; + + trans2utf(env, 1, 0, (char *) sqlite3_value_text(args[i]), + &arg); + (*env)->SetObjectArrayElement(env, arr, i, arg.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + (*env)->DeleteLocalRef(env, arg.jstr); + } + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr); + (*env)->DeleteLocalRef(env, arr); + (*env)->DeleteLocalRef(env, cls); + } +} + +static void +call3_func(sqlite3_context *sf, int nargs, sqlite3_value **args) +{ + call3_common(sf, 0, nargs, args); +} + +static void +call3_step(sqlite3_context *sf, int nargs, sqlite3_value **args) +{ + call3_common(sf, 1, nargs, args); +} + +static void +call3_final(sqlite3_context *sf) +{ + hfunc *f = (hfunc *) sqlite3_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = (*env)->GetMethodID(env, cls, "last_step", + "(LSQLite/FunctionContext;)V"); + if (mid == 0) { + (*env)->DeleteLocalRef(env, cls); + return; + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc); + (*env)->DeleteLocalRef(env, cls); + } +} +#endif + +static void +mkfunc_common(JNIEnv *env, int isagg, jobject obj, jstring name, + jint nargs, jobject fi) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + jclass cls = (*env)->FindClass(env, "SQLite/FunctionContext"); + jobject fc; + hfunc *f; + int ret; + transstr namestr; + jvalue v; + jthrowable exc; + + fc = (*env)->AllocObject(env, cls); + if (!fi) { + throwex(env, "null SQLite.Function not allowed"); + return; + } + f = malloc(sizeof (hfunc)); + if (!f) { + throwoom(env, "unable to get SQLite.FunctionContext handle"); + return; + } + globrefset(env, fc, &f->fc); + globrefset(env, fi, &f->fi); + globrefset(env, obj, &f->db); + f->h = h; + f->next = h->funcs; + h->funcs = f; + f->sf = 0; + f->env = env; + v.j = 0; + v.l = (jobject) f; + (*env)->SetLongField(env, f->fc, F_SQLite_FunctionContext_handle, v.j); + trans2iso(env, h->haveutf, h->enc, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + f->is3 = h->is3; + if (h->is3) { + ret = sqlite3_create_function((sqlite3 *) h->sqlite, + namestr.result, + (int) nargs, + SQLITE_UTF8, f, + isagg ? NULL : call3_func, + isagg ? call3_step : NULL, + isagg ? call3_final : NULL); + + } else { + if (isagg) { + ret = sqlite_create_aggregate((sqlite *) h->sqlite, + namestr.result, + (int) nargs, + call_step, call_final, f); + } else { + ret = sqlite_create_function((sqlite *) h->sqlite, + namestr.result, + (int) nargs, + call_func, f); + } + } +#else +#if HAVE_SQLITE2 + if (isagg) { + ret = sqlite_create_aggregate((sqlite *) h->sqlite, namestr.result, + (int) nargs, + call_step, call_final, f); + } else { + ret = sqlite_create_function((sqlite *) h->sqlite, namestr.result, + (int) nargs, + call_func, f); + } +#endif +#if HAVE_SQLITE3 + ret = sqlite3_create_function((sqlite3 *) h->sqlite, + namestr.result, + (int) nargs, + SQLITE_UTF8, f, + isagg ? NULL : call3_func, + isagg ? call3_step : NULL, + isagg ? call3_final : NULL); +#endif +#endif + transfree(&namestr); + if (ret != SQLITE_OK) { + throwex(env, "error creating function/aggregate"); + } + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1create_1aggregate(JNIEnv *env, jobject obj, + jstring name, jint nargs, jobject fi) +{ + mkfunc_common(env, 1, obj, name, nargs, fi); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1create_1function(JNIEnv *env, jobject obj, + jstring name, jint nargs, jobject fi) +{ + mkfunc_common(env, 0, obj, name, nargs, fi); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1function_1type(JNIEnv *env, jobject obj, + jstring name, jint type) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return; + } +#endif +#if HAVE_SQLITE2 +#if HAVE_SQLITE_FUNCTION_TYPE + { + int ret; + transstr namestr; + jthrowable exc; + + trans2iso(env, h->haveutf, h->enc, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite_function_type(h->sqlite, namestr.result, (int) type); + transfree(&namestr); + if (ret != SQLITE_OK) { + throwex(env, sqlite_error_string(ret)); + } + } +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT jint JNICALL +Java_SQLite_FunctionContext_count(JNIEnv *env, jobject obj) +{ + hfunc *f = getfunc(env, obj); + jint r = 0; + + if (f && f->sf) { +#if HAVE_SQLITE_BOTH + if (f->is3) { + r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf); + } else { + r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf); + } +#else +#if HAVE_SQLITE2 + r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf); +#endif +#if HAVE_SQLITE3 + r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf); +#endif +#endif + } + return r; +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1error(JNIEnv *env, jobject obj, jstring err) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + transstr errstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_error((sqlite_func *) f->sf, + errstr.result, -1); + transfree(&errstr); + } else if (err) { + jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, err, 0); + + sqlite3_result_error16((sqlite3_context *) f->sf, str, len); + (*env)->ReleaseStringChars(env, err, str); + } else { + sqlite3_result_error((sqlite3_context *) f->sf, + "null error text", -1); + } +#else +#if HAVE_SQLITE2 + transstr errstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_error((sqlite_func *) f->sf, errstr.result, -1); + transfree(&errstr); +#endif +#if HAVE_SQLITE3 + if (err) { + jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, err, 0); + + sqlite3_result_error16((sqlite3_context *) f->sf, str, len); + (*env)->ReleaseStringChars(env, err, str); + } else { + sqlite3_result_error((sqlite3_context *) f->sf, + "null error text", -1); + } +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__D(JNIEnv *env, jobject obj, jdouble d) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (f->is3) { + sqlite3_result_double((sqlite3_context *) f->sf, (double) d); + } else { + sqlite_set_result_double((sqlite_func *) f->sf, (double) d); + } +#else +#if HAVE_SQLITE2 + sqlite_set_result_double((sqlite_func *) f->sf, (double) d); +#endif +#if HAVE_SQLITE3 + sqlite3_result_double((sqlite3_context *) f->sf, (double) d); +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__I(JNIEnv *env, jobject obj, jint i) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (f->is3) { + sqlite3_result_int((sqlite3_context *) f->sf, (int) i); + } else { + sqlite_set_result_int((sqlite_func *) f->sf, (int) i); + } +#else +#if HAVE_SQLITE2 + sqlite_set_result_int((sqlite_func *) f->sf, (int) i); +#endif +#if HAVE_SQLITE3 + sqlite3_result_int((sqlite3_context *) f->sf, (int) i); +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2(JNIEnv *env, + jobject obj, + jstring ret) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + transstr retstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_string((sqlite_func *) f->sf, + retstr.result, -1); + transfree(&retstr); + } else if (ret) { + jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, ret, 0); + + sqlite3_result_text16((sqlite3_context *) f->sf, str, len, + SQLITE_TRANSIENT); + (*env)->ReleaseStringChars(env, ret, str); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } +#else +#if HAVE_SQLITE2 + transstr retstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_string((sqlite_func *) f->sf, retstr.result, -1); + transfree(&retstr); +#endif +#if HAVE_SQLITE3 + if (ret) { + jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, ret, 0); + + sqlite3_result_text16((sqlite3_context *) f->sf, str, len, + SQLITE_TRANSIENT); + (*env)->ReleaseStringChars(env, ret, str); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result___3B(JNIEnv *env, jobject obj, + jbyteArray b) +{ +#if HAVE_SQLITE3 + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + /* silently ignored */ + return; + } +#endif + if (b) { + jsize len; + jbyte *data; + + len = (*env)->GetArrayLength(env, b); + data = (*env)->GetByteArrayElements(env, b, 0); + sqlite3_result_blob((sqlite3_context *) f->sf, + data, len, SQLITE_TRANSIENT); + (*env)->ReleaseByteArrayElements(env, b, data, 0); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } + } +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result_1zeroblob(JNIEnv *env, jobject obj, + jint n) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_RESULT_ZEROBLOB + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + /* silently ignored */ + return; + } +#endif + sqlite3_result_zeroblob((sqlite3_context *) f->sf, n); + } +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_error_1string(JNIEnv *env, jclass c, jint err) +{ +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_error_string((int) err)); +#else + return (*env)->NewStringUTF(env, "unkown error"); +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database__1errmsg(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (!h->is3) { + return 0; + } +#endif + return (*env)->NewStringUTF(env, + sqlite3_errmsg((sqlite3 *) h->sqlite)); + } +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1set_1encoding(JNIEnv *env, jobject obj, jstring enc) +{ + handle *h = gethandle(env, obj); + + if (h && !h->haveutf) { +#if HAVE_BOTH_SQLITE + if (!h->is3) { + delglobrefp(env, &h->enc); + h->enc = enc; + globrefset(env, enc, &h->enc); + } +#else +#if HAVE_SQLITE2 + delglobrefp(env, &h->enc); + h->enc = enc; + globrefset(env, enc, &h->enc); +#endif +#endif + } +} + +#if HAVE_SQLITE_SET_AUTHORIZER +static int +doauth(void *arg, int what, const char *arg1, const char *arg2, + const char *arg3, const char *arg4) +{ + handle *h = (handle *) arg; + JNIEnv *env = h->env; + + if (env && h->ai) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->ai); + jmethodID mid; + jint i = what; + + mid = (*env)->GetMethodID(env, cls, "authorize", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I"); + if (mid) { + jstring s1 = 0, s2 = 0, s3 = 0, s4 = 0; + transstr tr; + + if (arg1) { + trans2utf(env, h->haveutf, h->enc, arg1, &tr); + s1 = tr.jstr; + } + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + if (arg2) { + trans2utf(env, h->haveutf, h->enc, arg2, &tr); + s2 = tr.jstr; + } + if (arg3) { + trans2utf(env, h->haveutf, h->enc, arg3, &tr); + s3 = tr.jstr; + } + if (arg4) { + trans2utf(env, h->haveutf, h->enc, arg4, &tr); + s4 = tr.jstr; + } + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + i = (*env)->CallIntMethod(env, h->ai, mid, i, s1, s2, s3, s4); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + (*env)->DeleteLocalRef(env, s4); + (*env)->DeleteLocalRef(env, s3); + (*env)->DeleteLocalRef(env, s2); + (*env)->DeleteLocalRef(env, s1); + if (i != SQLITE_OK && i != SQLITE_IGNORE) { + i = SQLITE_DENY; + } + return (int) i; + } + } + return SQLITE_DENY; +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Database__1set_1authorizer(JNIEnv *env, jobject obj, jobject auth) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->ai); + globrefset(env, auth, &h->ai); +#if HAVE_SQLITE_SET_AUTHORIZER + h->env = env; +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_set_authorizer((sqlite3 *) h->sqlite, + h->ai ? doauth : 0, h); + } else { + sqlite_set_authorizer((sqlite *) h->sqlite, + h->ai ? doauth : 0, h); + } +#else +#if HAVE_SQLITE2 + sqlite_set_authorizer((sqlite *) h->sqlite, h->ai ? doauth : 0, h); +#endif +#if HAVE_SQLITE3 + sqlite3_set_authorizer((sqlite3 *) h->sqlite, h->ai ? doauth : 0, h); +#endif +#endif +#endif + return; + } + throwclosed(env); +} + +#if HAVE_SQLITE_TRACE +static void +dotrace(void *arg, const char *msg) +{ + handle *h = (handle *) arg; + JNIEnv *env = h->env; + + if (env && h->tr && msg) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->tr); + jmethodID mid; + + mid = (*env)->GetMethodID(env, cls, "trace", "(Ljava/lang/String;)V"); + if (mid) { + transstr tr; + + trans2utf(env, h->haveutf, h->enc, msg, &tr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + (*env)->ExceptionClear(env); + return; + } + (*env)->CallVoidMethod(env, h->tr, mid, tr.jstr); + (*env)->ExceptionClear(env); + (*env)->DeleteLocalRef(env, tr.jstr); + return; + } + } + return; +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Database__1trace(JNIEnv *env, jobject obj, jobject tr) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->tr); + globrefset(env, tr, &h->tr); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h); + } else { +#if HAVE_SQLITE_TRACE + sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h); +#endif + } +#else +#if HAVE_SQLITE2 +#if HAVE_SQLITE_TRACE + sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h); +#endif +#endif +#if HAVE_SQLITE3 + sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h); +#endif +#endif + return; + } + throwclosed(env); +} + +#if HAVE_SQLITE_COMPILE +static void +dovmfinal(JNIEnv *env, jobject obj, int final) +{ + hvm *v = gethvm(env, obj); + + if (v) { + if (v->h) { + handle *h = v->h; + hvm *vv, **vvp; + + vvp = &h->vms; + vv = *vvp; + while (vv) { + if (vv == v) { + *vvp = vv->next; + break; + } + vvp = &vv->next; + vv = *vvp; + } + } + if (v->vm) { +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + free(v); + (*env)->SetLongField(env, obj, F_SQLite_Vm_handle, 0); + return; + } + if (!final) { + throwex(env, "vm already closed"); + } +} +#endif + +#if HAVE_SQLITE3 +static void +dostmtfinal(JNIEnv *env, jobject obj) +{ + hvm *v = gethstmt(env, obj); + + if (v) { + if (v->h) { + handle *h = v->h; + hvm *vv, **vvp; + + vvp = &h->vms; + vv = *vvp; + while (vv) { + if (vv == v) { + *vvp = vv->next; + break; + } + vvp = &vv->next; + vv = *vvp; + } + } + if (v->vm) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } + v->vm = 0; + free(v); + (*env)->SetLongField(env, obj, F_SQLite_Stmt_handle, 0); + } +} +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void +doblobfinal(JNIEnv *env, jobject obj) +{ + hbl *bl = gethbl(env, obj); + + if (bl) { + if (bl->h) { + handle *h = bl->h; + hbl *blc, **blp; + + blp = &h->blobs; + blc = *blp; + while (blc) { + if (blc == bl) { + *blp = blc->next; + break; + } + blp = &blc->next; + blc = *blp; + } + } + if (bl->blob) { + sqlite3_blob_close(bl->blob); + } + bl->blob = 0; + free(bl); + (*env)->SetLongField(env, obj, F_SQLite_Blob_handle, 0); + (*env)->SetIntField(env, obj, F_SQLite_Blob_size, 0); + } +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Vm_stop(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + dovmfinal(env, obj, 0); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Vm_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + dovmfinal(env, obj, 1); +#endif +} + +#if HAVE_SQLITE_COMPILE +#if HAVE_SQLITE3 +static void +free_tab(void *mem) +{ + char **p = (char **) mem; + int i, n; + + if (!p) { + return; + } + p -= 1; + mem = (void *) p; + n = ((int *) p)[0]; + p += n * 2 + 2 + 1; + for (i = 0; i < n; i++) { + if (p[i]) { + free(p[i]); + } + } + free(mem); +} +#endif +#endif + +JNIEXPORT jboolean JNICALL +Java_SQLite_Vm_step(JNIEnv *env, jobject obj, jobject cb) +{ +#if HAVE_SQLITE_COMPILE + hvm *v = gethvm(env, obj); + + if (v && v->vm && v->h) { + jthrowable exc; + int ret, ncol = 0; +#if HAVE_SQLITE3 + freemem *freeproc = 0; + const char **blob = 0; +#endif + const char **data = 0, **cols = 0; + + v->h->env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + if (ncol > 0) { + data = calloc(ncol * 3 + 3 + 1, sizeof (char *)); + if (data) { + data[0] = (const char *) ncol; + ++data; + cols = data + ncol + 1; + blob = cols + ncol + 1; + freeproc = free_tab; + } else { + ret = SQLITE_NOMEM; + } + } + if (ret != SQLITE_NOMEM) { + int i; + + for (i = 0; i < ncol; i++) { + cols[i] = + sqlite3_column_name((sqlite3_stmt *) v->vm, i); + if (sqlite3_column_type((sqlite3_stmt *) v->vm, i) + == SQLITE_BLOB) { + unsigned char *src = (unsigned char *) + sqlite3_column_blob((sqlite3_stmt *) v->vm, i); + int n = + sqlite3_column_bytes((sqlite3_stmt *) v->vm, + i); + + if (src) { + data[i] = malloc(n * 2 + 4); + if (data[i]) { + int k; + char *p = (char *) data[i]; + + blob[i] = data[i]; + *p++ = 'X'; + *p++ = '\''; + for (k = 0; k < n; k++) { + *p++ = xdigits[src[k] >> 4]; + *p++ = xdigits[src[k] & 0x0F]; + } + *p++ = '\''; + *p++ = '\0'; + } + } + } else { + data[i] = (const char *) + sqlite3_column_text((sqlite3_stmt *) v->vm, i); + } + } + } + } + } else { + ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols); + } +#else +#if HAVE_SQLITE2 + ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols); +#endif +#if HAVE_SQLITE3 + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + if (ncol > 0) { + data = calloc(ncol * 3 + 3 + 1, sizeof (char *)); + if (data) { + data[0] = (const char *) ncol; + ++data; + cols = data + ncol + 1; + blob = cols + ncol + 1; + freeproc = free_tab; + } else { + ret = SQLITE_NOMEM; + } + } + if (ret != SQLITE_NOMEM) { + int i; + + for (i = 0; i < ncol; i++) { + cols[i] = sqlite3_column_name((sqlite3_stmt *) v->vm, i); + if (sqlite3_column_type((sqlite3_stmt *) v->vm, i) + == SQLITE_BLOB) { + unsigned char *src = (unsigned char *) + sqlite3_column_blob((sqlite3_stmt *) v->vm, i); + int n = + sqlite3_column_bytes((sqlite3_stmt *) v->vm, i); + + if (src) { + data[i] = malloc(n * 2 + 4); + if (data[i]) { + int k; + char *p = (char *) data[i]; + + blob[i] = data[i]; + *p++ = 'X'; + *p++ = '\''; + for (k = 0; k < n; k++) { + *p++ = xdigits[src[k] >> 4]; + *p++ = xdigits[src[k] & 0x0F]; + } + *p++ = '\''; + *p++ = '\0'; + } + } + } else { + data[i] = (char *) + sqlite3_column_text((sqlite3_stmt *) v->vm, i); + } + } + } + } +#endif +#endif + if (ret == SQLITE_ROW) { + v->hh.cb = cb; + v->hh.env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { + v->hh.stmt = (sqlite3_stmt *) v->vm; + } +#else +#if HAVE_SQLITE3 + v->hh.stmt = (sqlite3_stmt *) v->vm; +#endif +#endif + callback((void *) &v->hh, ncol, (char **) data, (char **) cols); +#if HAVE_SQLITE3 + if (data && freeproc) { + freeproc((void *) data); + } +#endif + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + goto dofin; + } + return JNI_TRUE; + } else if (ret == SQLITE_DONE) { +dofin: +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + return JNI_FALSE; + } +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + setvmerr(env, obj, ret); + v->vm = 0; + throwex(env, "error in step"); + return JNI_FALSE; + } + throwex(env, "vm already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Vm_compile(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + hvm *v = gethvm(env, obj); + void *svm = 0; + char *err = 0; + const char *tail; + int ret; + + if (v && v->vm) { +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + if (v && v->h && v->h->sqlite) { + if (!v->tail) { + return JNI_FALSE; + } + v->h->env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite, v->tail, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) v->h->sqlite, v->tail, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } else { + ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail, + &tail, (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } + } +#else +#if HAVE_SQLITE2 + ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail, + &tail, (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } +#endif +#if HAVE_SQLITE3 +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } +#endif +#endif + if (ret != SQLITE_OK) { + setvmerr(env, obj, ret); + v->tail = 0; + throwex(env, err ? err : "error in compile/prepare"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + return JNI_FALSE; + } +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (!svm) { + v->tail = 0; + return JNI_FALSE; + } + v->vm = svm; + v->tail = (char *) tail; + v->hh.row1 = 1; + return JNI_TRUE; + } + throwex(env, "vm already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_vm_1compile(JNIEnv *env, jobject obj, jstring sql, + jobject vm) +{ +#if HAVE_SQLITE_COMPILE + handle *h = gethandle(env, obj); + void *svm = 0; + hvm *v; + char *err = 0; + const char *tail; + transstr tr; + jvalue vv; + int ret; + jthrowable exc; + + if (!h) { + throwclosed(env); + return; + } + if (!vm) { + throwex(env, "null vm"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } + trans2iso(env, h->haveutf, h->enc, sql, &tr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + h->env = env; +#if HAVE_BOTH_SQLITE + if (h->is3) { +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } else { + ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, + (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + } + } + } +#else +#if HAVE_SQLITE2 + ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, + (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } +#endif +#if HAVE_SQLITE3 +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } +#endif +#endif + if (ret != SQLITE_OK) { + transfree(&tr); + setvmerr(env, vm, ret); + throwex(env, err ? err : "error in prepare/compile"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + return; + } +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (!svm) { + transfree(&tr); + return; + } + v = malloc(sizeof (hvm) + strlen(tail) + 1); + if (!v) { + transfree(&tr); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_finalize((sqlite3_stmt *) svm); + } else { + sqlite_finalize((sqlite_vm *) svm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) svm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) svm); +#endif +#endif + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = h->is3; +#endif + strcpy(v->tail, tail); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_vm_1compile_1args(JNIEnv *env, + jobject obj, jstring sql, + jobject vm, jobjectArray args) +{ +#if HAVE_SQLITE_COMPILE +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); +#endif + +#if HAVE_BOTH_SQLITE + if (h && !h->is3) { + throwex(env, "unsupported"); + return; + } +#else +#if HAVE_SQLITE2 + throwex(env, "unsupported"); +#endif +#endif +#if HAVE_SQLITE3 + if (!h || !h->sqlite) { + throwclosed(env); + return; + } + if (!vm) { + throwex(env, "null vm"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } else { + void *svm = 0; + hvm *v; + jvalue vv; + jthrowable exc; + int rc = SQLITE_ERROR, nargs, i; + char *p; + const char *str = (*env)->GetStringUTFChars(env, sql, NULL); + const char *tail; + transstr sqlstr; + struct args { + char *arg; + jobject obj; + transstr trans; + } *argv = 0; + char **cargv = 0; + + p = (char *) str; + nargs = 0; + while (*p) { + if (*p == '%') { + ++p; + if (*p == 'q' || *p == 'Q' || *p == 's') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwex(env, "too much SQL parameters"); + return; + } + } else if (*p != '%') { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwex(env, "bad % specification in query"); + return; + } + } + ++p; + } + cargv = malloc((sizeof (*argv) + sizeof (char *)) * MAX_PARAMS); + if (!cargv) { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwoom(env, "unable to allocate arg vector"); + return; + } + argv = (struct args *) (cargv + MAX_PARAMS); + for (i = 0; i < MAX_PARAMS; i++) { + cargv[i] = 0; + argv[i].arg = 0; + argv[i].obj = 0; + argv[i].trans.result = argv[i].trans.tofree = 0; + } + exc = 0; + for (i = 0; i < nargs; i++) { + jobject so = (*env)->GetObjectArrayElement(env, args, i); + + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + break; + } + if (so) { + argv[i].obj = so; + argv[i].arg = cargv[i] = + trans2iso(env, 1, 0, argv[i].obj, &argv[i].trans); + } + } + if (exc) { + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + (*env)->ReleaseStringUTFChars(env, sql, str); + return; + } + h->row1 = 1; + trans2iso(env, 1, 0, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (!exc) { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + if (!s) { + rc = SQLITE_NOMEM; + } else { +#if HAVE_SQLITE3_PREPARE_V2 + rc = sqlite3_prepare_v2((sqlite3 *) h->sqlite, s, -1, + (sqlite3_stmt **) &svm, &tail); +#else + rc = sqlite3_prepare((sqlite3 *) h->sqlite, s, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (rc != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } + if (rc != SQLITE_OK) { + sqlite3_free(s); + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + setvmerr(env, vm, rc); + throwex(env, "error in prepare"); + return; + } + v = malloc(sizeof (hvm) + strlen(tail) + 1); + if (!v) { + sqlite3_free(s); + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + sqlite3_finalize((sqlite3_stmt *) svm); + setvmerr(env, vm, SQLITE_NOMEM); + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = h->is3; +#endif + strcpy(v->tail, tail); + sqlite3_free(s); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j); + } + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + } + } +#endif +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_FunctionContext_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1progress_1handler(JNIEnv *env, jobject obj, jint n, + jobject ph) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + /* CHECK THIS */ +#if HAVE_SQLITE_PROGRESS_HANDLER + delglobrefp(env, &h->ph); +#if HAVE_BOTH_SQLITE + if (h->is3) { + if (ph) { + globrefset(env, ph, &h->ph); + sqlite3_progress_handler((sqlite3 *) h->sqlite, + n, progresshandler, h); + } else { + sqlite3_progress_handler((sqlite3 *) h->sqlite, + 0, 0, 0); + } + } else { + if (ph) { + globrefset(env, ph, &h->ph); + sqlite_progress_handler((sqlite *) h->sqlite, + n, progresshandler, h); + } else { + sqlite_progress_handler((sqlite *) h->sqlite, + 0, 0, 0); + } + } +#else +#if HAVE_SQLITE2 + if (ph) { + globrefset(env, ph, &h->ph); + sqlite_progress_handler((sqlite *) h->sqlite, + n, progresshandler, h); + } else { + sqlite_progress_handler((sqlite *) h->sqlite, + 0, 0, 0); + } +#endif +#if HAVE_SQLITE3 + if (ph) { + globrefset(env, ph, &h->ph); + sqlite3_progress_handler((sqlite3 *) h->sqlite, + n, progresshandler, h); + } else { + sqlite3_progress_handler((sqlite3 *) h->sqlite, + 0, 0, 0); + } +#endif +#endif + return; +#else + throwex(env, "unsupported"); + return; +#endif + } + throwclosed(env); +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Database_is3(JNIEnv *env, jobject obj) +{ +#if HAVE_BOTH_SQLITE + handle *h = gethandle(env, obj); + + if (h) { + return h->is3 ? JNI_TRUE : JNI_FALSE; + } + return JNI_FALSE; +#else +#if HAVE_SQLITE2 + return JNI_FALSE; +#endif +#if HAVE_SQLITE3 + return JNI_TRUE; +#endif +#endif +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Stmt_prepare(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 + hvm *v = gethstmt(env, obj); + void *svm = 0; + char *tail; + int ret; + + if (v && v->vm) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + v->vm = 0; + } + if (v && v->h && v->h->sqlite) { + if (!v->tail) { + return JNI_FALSE; + } + v->h->env = env; +#if HAVE_SQLITE3_PREPARE16_V2 + ret = sqlite3_prepare16_v2((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, + (const void **) &tail); +#else + ret = sqlite3_prepare16((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, + (const void **) &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + v->tail = 0; + throwex(env, err ? err : "error in compile/prepare"); + return JNI_FALSE; + } + if (!svm) { + v->tail = 0; + return JNI_FALSE; + } + v->vm = svm; + v->tail = (char *) tail; + v->hh.row1 = 1; + return JNI_TRUE; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_stmt_1prepare(JNIEnv *env, jobject obj, jstring sql, + jobject stmt) +{ +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); + void *svm = 0; + hvm *v; + jvalue vv; + jsize len16; + const jchar *sql16, *tail = 0; + int ret; + + if (!h) { + throwclosed(env); + return; + } + if (!stmt) { + throwex(env, "null stmt"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } +#ifdef HAVE_BOTH_SQLITE + if (!h->is3) { + throwex(env, "only on SQLite3 database"); + return; + } +#endif + len16 = (*env)->GetStringLength(env, sql) * sizeof (jchar); + if (len16 < 1) { + return; + } + h->env = env; + sql16 = (*env)->GetStringChars(env, sql, 0); +#if HAVE_SQLITE3_PREPARE16_V2 + ret = sqlite3_prepare16_v2((sqlite3 *) h->sqlite, sql16, len16, + (sqlite3_stmt **) &svm, (const void **) &tail); +#else + ret = sqlite3_prepare16((sqlite3 *) h->sqlite, sql16, len16, + (sqlite3_stmt **) &svm, (const void **) &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(h->sqlite); + + (*env)->ReleaseStringChars(env, sql, sql16); + setstmterr(env, stmt, ret); + throwex(env, err ? err : "error in prepare"); + return; + } + if (!svm) { + (*env)->ReleaseStringChars(env, sql, sql16); + return; + } + len16 = len16 + sizeof (jchar) - ((char *) tail - (char *) sql16); + if (len16 < (jsize) sizeof (jchar)) { + len16 = sizeof (jchar); + } + v = malloc(sizeof (hvm) + len16); + if (!v) { + (*env)->ReleaseStringChars(env, sql, sql16); + sqlite3_finalize((sqlite3_stmt *) svm); + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = 1; +#endif + memcpy(v->tail, tail, len16); + len16 /= sizeof (jchar); + ((jchar *) v->tail)[len16 - 1] = 0; + (*env)->ReleaseStringChars(env, sql, sql16); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, stmt, F_SQLite_Stmt_handle, vv.j); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Stmt_step(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ret; + + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + return JNI_TRUE; + } + if (ret != SQLITE_DONE) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + throwex(env, err ? err : "error in step"); + } + return JNI_FALSE; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_close(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ret; + + ret = sqlite3_finalize((sqlite3_stmt *) v->vm); + v->vm = 0; + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + throwex(env, err ? err : "error in close"); + } + return; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_reset(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + sqlite3_reset((sqlite3_stmt *) v->vm); + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_clear_1bindings(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_CLEAR_BINDINGS + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + sqlite3_clear_bindings((sqlite3_stmt *) v->vm); + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__II(JNIEnv *env, jobject obj, jint pos, jint val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_int((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__IJ(JNIEnv *env, jobject obj, jint pos, jlong val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_int64((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__ID(JNIEnv *env, jobject obj, jint pos, jdouble val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_double((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__I_3B(JNIEnv *env, jobject obj, jint pos, jbyteArray val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + jint len; + char *data = 0; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + if (val) { + len = (*env)->GetArrayLength(env, val); + if (len > 0) { + data = sqlite3_malloc(len); + if (!data) { + throwoom(env, "unable to get blob parameter"); + return; + } + (*env)->GetByteArrayRegion(env, val, 0, len, (jbyte *) data); + ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm, + pos, data, len, sqlite3_free); + } else { + ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm, + pos, "", 0, SQLITE_STATIC); + } + } else { + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + } + if (ret != SQLITE_OK) { + if (data) { + sqlite3_free(data); + } + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__ILjava_lang_String_2(JNIEnv *env, jobject obj, + jint pos, jstring val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + jsize len; + char *data = 0; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + if (val) { + const jsize charCount = (*env)->GetStringLength(env, val); + len = charCount * sizeof(jchar); + if (len > 0) { + data = sqlite3_malloc(len); + if (!data) { + throwoom(env, "unable to get blob parameter"); + return; + } + + (*env)->GetStringRegion(env, val, 0, charCount, (jchar*) data); + ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm, + pos, data, len, sqlite3_free); + } else { + ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm, pos, "", 0, + SQLITE_STATIC); + } + } else { + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + } + if (ret != SQLITE_OK) { + if (data) { + sqlite3_free(data); + } + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__I(JNIEnv *env, jobject obj, jint pos) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind_1zeroblob(JNIEnv *env, jobject obj, jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_ZEROBLOB + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_zeroblob((sqlite3_stmt *) v->vm, pos, len); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_bind_1parameter_1count(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + return sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_bind_1parameter_1name(JNIEnv *env, jobject obj, jint pos) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_NAME + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + const char *name; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return 0; + } + name = sqlite3_bind_parameter_name((sqlite3_stmt *) v->vm, pos); + if (name) { + return (*env)->NewStringUTF(env, name); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_bind_1parameter_1index(JNIEnv *env, jobject obj, + jstring name) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_INDEX + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int pos; + const char *n; + transstr namestr; + jthrowable exc; + + n = trans2iso(env, 1, 0, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return -1; + } + pos = sqlite3_bind_parameter_index((sqlite3_stmt *) v->vm, n); + transfree(&namestr); + return pos; + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif + return -1; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1int(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_int((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Stmt_column_1long(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_int64((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jdouble JNICALL +Java_SQLite_Stmt_column_1double(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_double((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jbyteArray JNICALL +Java_SQLite_Stmt_column_1bytes(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + int nbytes; + const jbyte *data; + jbyteArray b = 0; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + data = sqlite3_column_blob((sqlite3_stmt *) v->vm, col); + if (data) { + nbytes = sqlite3_column_bytes((sqlite3_stmt *) v->vm, col); + } else { + return 0; + } + b = (*env)->NewByteArray(env, nbytes); + if (!b) { + throwoom(env, "unable to get blob column data"); + return 0; + } + (*env)->SetByteArrayRegion(env, b, 0, nbytes, data); + return b; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1string(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + int nbytes; + const jchar *data; + jstring b = 0; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + data = sqlite3_column_text16((sqlite3_stmt *) v->vm, col); + if (data) { + nbytes = sqlite3_column_bytes16((sqlite3_stmt *) v->vm, col); + } else { + return 0; + } + nbytes /= sizeof (jchar); + b = (*env)->NewString(env, data, nbytes); + if (!b) { + throwoom(env, "unable to get string column data"); + return 0; + } + return b; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1type(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_type((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1count(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + return sqlite3_column_count((sqlite3_stmt *) v->vm); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1table_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_TABLE_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_table_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1database_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_DATABASE_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_database_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1decltype(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_decltype16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1origin_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_ORIGIN_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_origin_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + dostmtfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open_1blob(JNIEnv *env, jobject obj, + jstring dbname, jstring table, + jstring column, jlong row, + jboolean rw, jobject blobj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + handle *h = gethandle(env, obj); + hbl *bl; + jthrowable exc; + transstr dbn, tbl, col; + sqlite3_blob *blob; + jvalue vv; + int ret; + + if (!blobj) { + throwex(env, "null blob"); + return; + } + if (h && h->sqlite) { + trans2iso(env, h->haveutf, h->enc, dbname, &dbn); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + trans2iso(env, h->haveutf, h->enc, table, &tbl); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + transfree(&dbn); + (*env)->DeleteLocalRef(env, exc); + return; + } + trans2iso(env, h->haveutf, h->enc, column, &col); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + transfree(&tbl); + transfree(&dbn); + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite3_blob_open(h->sqlite, + dbn.result, tbl.result, col.result, + row, rw, &blob); + transfree(&col); + transfree(&tbl); + transfree(&dbn); + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(h->sqlite); + + seterr(env, obj, ret); + throwex(env, err ? err : "error in blob open"); + return; + } + bl = malloc(sizeof (hbl)); + if (!bl) { + sqlite3_blob_close(blob); + throwoom(env, "unable to get SQLite blob handle"); + return; + } + bl->next = h->blobs; + h->blobs = bl; + bl->blob = blob; + bl->h = h; + vv.j = 0; + vv.l = (jobject) bl; + (*env)->SetLongField(env, blobj, F_SQLite_Blob_handle, vv.j); + (*env)->SetIntField(env, blobj, F_SQLite_Blob_size, + sqlite3_blob_bytes(blob)); + return; + } + throwex(env, "not an open database"); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jint JNICALL +Java_SQLite_Blob_write(JNIEnv *env , jobject obj, jbyteArray b, jint off, + jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl = gethbl(env, obj); + + if (bl && bl->h && bl->blob) { + jbyte *buf; + jthrowable exc; + int ret; + + if (len <= 0) { + return 0; + } + buf = malloc(len); + if (!buf) { + throwoom(env, "out of buffer space for blob"); + return 0; + } + (*env)->GetByteArrayRegion(env, b, off, len, buf); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + free(buf); + return 0; + } + ret = sqlite3_blob_write(bl->blob, buf, len, pos); + free(buf); + if (ret != SQLITE_OK) { + throwioex(env, "blob write error"); + return 0; + } + return len; + } + throwex(env, "blob already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Blob_read(JNIEnv *env , jobject obj, jbyteArray b, jint off, + jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl = gethbl(env, obj); + + if (bl && bl->h && bl->blob) { + jbyte *buf; + jthrowable exc; + int ret; + + if (len <= 0) { + return 0; + } + buf = malloc(len); + if (!buf) { + throwoom(env, "out of buffer space for blob"); + return 0; + } + ret = sqlite3_blob_read(bl->blob, buf, len, pos); + if (ret != SQLITE_OK) { + free(buf); + throwioex(env, "blob read error"); + return 0; + } + (*env)->SetByteArrayRegion(env, b, off, len, buf); + free(buf); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + return 0; + } + return len; + } + throwex(env, "blob already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_close(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + doblobfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + doblobfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Stmt_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Stmt_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Vm_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Vm_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Vm_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Blob_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Blob_size = + (*env)->GetFieldID(env, cls, "size", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_internal_1init(JNIEnv *env, jclass cls) +{ +//#ifndef JNI_VERSION_1_2 + jclass jls = (*env)->FindClass(env, "java/lang/String"); + + C_java_lang_String = (*env)->NewGlobalRef(env, jls); +//#endif + F_SQLite_Database_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Database_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); + M_java_lang_String_getBytes = + (*env)->GetMethodID(env, C_java_lang_String, "getBytes", "()[B"); + M_java_lang_String_getBytes2 = + (*env)->GetMethodID(env, C_java_lang_String, "getBytes", + "(Ljava/lang/String;)[B"); + M_java_lang_String_initBytes = + (*env)->GetMethodID(env, C_java_lang_String, "<init>", "([B)V"); + M_java_lang_String_initBytes2 = + (*env)->GetMethodID(env, C_java_lang_String, "<init>", + "([BLjava/lang/String;)V"); +} + +#ifdef JNI_VERSION_1_2 +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) +{ + JNIEnv *env; + jclass cls; + +#ifndef _WIN32 +#if HAVE_SQLITE2 + if (strcmp(sqlite_libencoding(), "UTF-8") != 0) { + fprintf(stderr, "WARNING: using non-UTF SQLite2 engine\n"); + } +#endif +#endif + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) { + return JNI_ERR; + } + cls = (*env)->FindClass(env, "java/lang/String"); + if (!cls) { + return JNI_ERR; + } + C_java_lang_String = (*env)->NewWeakGlobalRef(env, cls); + return JNI_VERSION_1_2; +} + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved) +{ + JNIEnv *env; + + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) { + return; + } + if (C_java_lang_String) { + (*env)->DeleteWeakGlobalRef(env, C_java_lang_String); + C_java_lang_String = 0; + } +} +#endif diff --git a/sqlite-jdbc/src/main/native/sqlite_jni.h b/sqlite-jdbc/src/main/native/sqlite_jni.h new file mode 100644 index 0000000..cdb7692 --- /dev/null +++ b/sqlite-jdbc/src/main/native/sqlite_jni.h @@ -0,0 +1,657 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class SQLite_Database */ + +#ifndef _Included_SQLite_Database +#define _Included_SQLite_Database +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Database + * Method: _open + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: SQLite_Database + * Method: _open_aux_file + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open_1aux_1file + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Database + * Method: _finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _exec + * Signature: (Ljava/lang/String;LSQLite/Callback;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2 + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: _exec + * Signature: (Ljava/lang/String;LSQLite/Callback;[Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2 + (JNIEnv *, jobject, jstring, jobject, jobjectArray); + +/* + * Class: SQLite_Database + * Method: _last_insert_rowid + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Database__1last_1insert_1rowid + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _interrupt + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1interrupt + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _changes + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Database__1changes + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _busy_handler + * Signature: (LSQLite/BusyHandler;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1handler + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: _busy_timeout + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1timeout + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Database + * Method: _complete + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Database__1complete + (JNIEnv *, jclass, jstring); + +/* + * Class: SQLite_Database + * Method: version + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_version + (JNIEnv *, jclass); + +/* + * Class: SQLite_Database + * Method: dbversion + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_dbversion + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _create_function + * Signature: (Ljava/lang/String;ILSQLite/Function;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1create_1function + (JNIEnv *, jobject, jstring, jint, jobject); + +/* + * Class: SQLite_Database + * Method: _create_aggregate + * Signature: (Ljava/lang/String;ILSQLite/Function;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1create_1aggregate + (JNIEnv *, jobject, jstring, jint, jobject); + +/* + * Class: SQLite_Database + * Method: _function_type + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1function_1type + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: SQLite_Database + * Method: _errmsg + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database__1errmsg + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: error_string + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_error_1string + (JNIEnv *, jclass, jint); + +/* + * Class: SQLite_Database + * Method: _set_encoding + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1set_1encoding + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Database + * Method: _set_authorizer + * Signature: (LSQLite/Authorizer;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1set_1authorizer + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: _trace + * Signature: (LSQLite/Trace;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1trace + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: is3 + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Database_is3 + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: vm_compile + * Signature: (Ljava/lang/String;LSQLite/Vm;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: vm_compile_args + * Signature: (Ljava/lang/String;LSQLite/Vm;[Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile_1args + (JNIEnv *, jobject, jstring, jobject, jobjectArray); + +/* + * Class: SQLite_Database + * Method: stmt_prepare + * Signature: (Ljava/lang/String;LSQLite/Stmt;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_stmt_1prepare + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: _open_blob + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZLSQLite/Blob;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open_1blob + (JNIEnv *, jobject, jstring, jstring, jstring, jlong, jboolean, jobject); + +/* + * Class: SQLite_Database + * Method: _progress_handler + * Signature: (ILSQLite/ProgressHandler;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1progress_1handler + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: SQLite_Database + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Vm */ + +#ifndef _Included_SQLite_Vm +#define _Included_SQLite_Vm +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Vm + * Method: step + * Signature: (LSQLite/Callback;)Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Vm_step + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Vm + * Method: compile + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Vm_compile + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: stop + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_stop + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_FunctionContext */ + +#ifndef _Included_SQLite_FunctionContext +#define _Included_SQLite_FunctionContext +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2 + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__I + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (D)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__D + (JNIEnv *, jobject, jdouble); + +/* + * Class: SQLite_FunctionContext + * Method: set_error + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1error + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: ([B)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result___3B + (JNIEnv *, jobject, jbyteArray); + +/* + * Class: SQLite_FunctionContext + * Method: set_result_zeroblob + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result_1zeroblob + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_FunctionContext + * Method: count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_FunctionContext_count + (JNIEnv *, jobject); + +/* + * Class: SQLite_FunctionContext + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Stmt */ + +#ifndef _Included_SQLite_Stmt +#define _Included_SQLite_Stmt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Stmt + * Method: prepare + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_prepare + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: step + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_step + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: reset + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_reset + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: clear_bindings + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_clear_1bindings + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__II + (JNIEnv *, jobject, jint, jint); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__IJ + (JNIEnv *, jobject, jint, jlong); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (ID)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ID + (JNIEnv *, jobject, jint, jdouble); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I_3B + (JNIEnv *, jobject, jint, jbyteArray); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ILjava_lang_String_2 + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_zeroblob + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind_1zeroblob + (JNIEnv *, jobject, jint, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1count + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_bind_1parameter_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_index + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1index + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Stmt + * Method: column_int + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1int + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_long + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Stmt_column_1long + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_double + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_SQLite_Stmt_column_1double + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_bytes + * Signature: (I)[B + */ +JNIEXPORT jbyteArray JNICALL Java_SQLite_Stmt_column_1bytes + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_string + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1string + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_type + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1type + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1count + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: column_table_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1table_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_database_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1database_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_decltype + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1decltype + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_origin_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1origin_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Blob */ + +#ifndef _Included_SQLite_Blob +#define _Included_SQLite_Blob +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Blob + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Blob + * Method: write + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Blob_write + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: SQLite_Blob + * Method: read + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Blob_read + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: SQLite_Blob + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Blob + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/sqlite-jdbc/src/main/native/sqlite_jni_defs.h b/sqlite-jdbc/src/main/native/sqlite_jni_defs.h new file mode 100644 index 0000000..91b2378 --- /dev/null +++ b/sqlite-jdbc/src/main/native/sqlite_jni_defs.h @@ -0,0 +1,39 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define HAVE_SQLITE2 0 +#define HAVE_SQLITE3 1 +#define HAVE_SQLITE_FUNCTION_TYPE 0 +#define HAVE_SQLITE_OPEN_AUX_FILE 0 +#define HAVE_SQLITE_SET_AUTHORIZER 0 +#define HAVE_SQLITE_TRACE 0 +#define HAVE_SQLITE_COMPILE 0 +#define HAVE_SQLITE_PROGRESS_HANDLER 0 +#define HAVE_SQLITE3_MALLOC 1 +#define HAVE_SQLITE3_PREPARE_V2 0 +#define HAVE_SQLITE3_PREPARE16_V2 0 +#define HAVE_SQLITE3_BIND_ZEROBLOB 0 +#define HAVE_SQLITE3_CLEAR_BINDINGS 0 +#define HAVE_SQLITE3_COLUMN_TABLE_NAME16 0 +#define HAVE_SQLITE3_COLUMN_DATABASE_NAME16 0 +#define HAVE_SQLITE3_COLUMN_ORIGIN_NAME16 0 +#define HAVE_SQLITE3_BIND_PARAMETER_COUNT 1 +#define HAVE_SQLITE3_BIND_PARAMETER_NAME 1 +#define HAVE_SQLITE3_BIND_PARAMETER_INDEX 1 +#define HAVE_SQLITE3_RESULT_ZEROBLOB 0 +#define HAVE_SQLITE3_INCRBLOBIO 0 + + |