<modelVersion>4.0.0</modelVersion>\r
<groupId>org.xerial</groupId>\r
<artifactId>sqlite-jdbc</artifactId>\r
- <version>v038</version>\r
+ <version>v038.1</version>\r
<name>SQLite JDBC</name>\r
<description>SQLite JDBC library</description>\r
\r
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+interface Codes
+{
+ /** Successful result */
+ public static final int SQLITE_OK = 0;
+
+ /** SQL error or missing database */
+ public static final int SQLITE_ERROR = 1;
+
+ /** An internal logic error in SQLite */
+ public static final int SQLITE_INTERNAL = 2;
+
+ /** Access permission denied */
+ public static final int SQLITE_PERM = 3;
+
+ /** Callback routine requested an abort */
+ public static final int SQLITE_ABORT = 4;
+
+ /** The database file is locked */
+ public static final int SQLITE_BUSY = 5;
+
+ /** A table in the database is locked */
+ public static final int SQLITE_LOCKED = 6;
+
+ /** A malloc() failed */
+ public static final int SQLITE_NOMEM = 7;
+
+ /** Attempt to write a readonly database */
+ public static final int SQLITE_READONLY = 8;
+
+ /** Operation terminated by sqlite_interrupt() */
+ public static final int SQLITE_INTERRUPT = 9;
+
+ /** Some kind of disk I/O error occurred */
+ public static final int SQLITE_IOERR = 10;
+
+ /** The database disk image is malformed */
+ public static final int SQLITE_CORRUPT = 11;
+
+ /** (Internal Only) Table or record not found */
+ public static final int SQLITE_NOTFOUND = 12;
+
+ /** Insertion failed because database is full */
+ public static final int SQLITE_FULL = 13;
+
+ /** Unable to open the database file */
+ public static final int SQLITE_CANTOPEN = 14;
+
+ /** Database lock protocol error */
+ public static final int SQLITE_PROTOCOL = 15;
+
+ /** (Internal Only) Database table is empty */
+ public static final int SQLITE_EMPTY = 16;
+
+ /** The database schema changed */
+ public static final int SQLITE_SCHEMA = 17;
+
+ /** Too much data for one row of a table */
+ public static final int SQLITE_TOOBIG = 18;
+
+ /** Abort due to constraint violation */
+ public static final int SQLITE_CONSTRAINT = 19;
+
+ /** Data type mismatch */
+ public static final int SQLITE_MISMATCH = 20;
+
+ /** Library used incorrectly */
+ public static final int SQLITE_MISUSE = 21;
+
+ /** Uses OS features not supported on host */
+ public static final int SQLITE_NOLFS = 22;
+
+ /** Authorization denied */
+ public static final int SQLITE_AUTH = 23;
+
+ /** sqlite_step() has another row ready */
+ public static final int SQLITE_ROW = 100;
+
+ /** sqlite_step() has finished executing */
+ public static final int SQLITE_DONE = 101;
+
+
+ // types returned by sqlite3_column_type()
+
+ public static final int SQLITE_INTEGER = 1;
+ public static final int SQLITE_FLOAT = 2;
+ public static final int SQLITE_TEXT = 3;
+ public static final int SQLITE_BLOB = 4;
+ public static final int SQLITE_NULL = 5;
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.io.File;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+
+class Conn implements Connection
+{
+ private final String url;
+ private DB db = null;
+ private MetaData meta = null;
+ private boolean autoCommit = true;
+ private int timeout = 0;
+
+ public Conn(String url, String filename) throws SQLException
+ {
+ // check the path to the file exists
+ if (!":memory:".equals(filename))
+ {
+ File file = new File(filename).getAbsoluteFile();
+ File parent = file.getParentFile();
+ if (parent != null && !parent.exists())
+ {
+ for (File up = parent; up != null && !up.exists();)
+ {
+ parent = up;
+ up = up.getParentFile();
+ }
+ throw new SQLException("path to '" + filename + "': '" + parent + "' does not exist");
+ }
+
+ // check write access if file does not exist
+ try
+ {
+ if (file.createNewFile())
+ file.delete();
+ }
+ catch (Exception e)
+ {
+ throw new SQLException("opening db: '" + filename + "': " + e.getMessage());
+ }
+ filename = file.getAbsolutePath();
+ }
+
+ // TODO: library variable to explicitly control load type
+ // attempt to use the Native library first
+ try
+ {
+ Class nativedb = Class.forName("org.sqlite.NativeDB");
+ if (((Boolean) nativedb.getDeclaredMethod("load", null).invoke(null, null)).booleanValue())
+ db = (DB) nativedb.newInstance();
+ }
+ catch (Exception e)
+ {} // fall through to nested library
+
+ // load nested library
+ if (db == null)
+ {
+ try
+ {
+ db = (DB) Class.forName("org.sqlite.NestedDB").newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new SQLException("no SQLite library found");
+ }
+ }
+
+ this.url = url;
+ db.open(filename);
+ setTimeout(3000);
+ }
+
+ int getTimeout()
+ {
+ return timeout;
+ }
+
+ void setTimeout(int ms) throws SQLException
+ {
+ timeout = ms;
+ db.busy_timeout(ms);
+ }
+
+ String url()
+ {
+ return url;
+ }
+
+ String libversion() throws SQLException
+ {
+ return db.libversion();
+ }
+
+ DB db()
+ {
+ return db;
+ }
+
+ private void checkOpen() throws SQLException
+ {
+ if (db == null)
+ throw new SQLException("database connection closed");
+ }
+
+ private void checkCursor(int rst, int rsc, int rsh) throws SQLException
+ {
+ if (rst != ResultSet.TYPE_FORWARD_ONLY)
+ throw new SQLException("SQLite only supports TYPE_FORWARD_ONLY cursors");
+ if (rsc != ResultSet.CONCUR_READ_ONLY)
+ throw new SQLException("SQLite only supports CONCUR_READ_ONLY cursors");
+ if (rsh != ResultSet.CLOSE_CURSORS_AT_COMMIT)
+ throw new SQLException("SQLite only supports closing cursors at commit");
+ }
+
+ public void finalize() throws SQLException
+ {
+ close();
+ }
+
+ public void close() throws SQLException
+ {
+ if (db == null)
+ return;
+ if (meta != null)
+ meta.close();
+
+ db.close();
+ db = null;
+ }
+
+ public boolean isClosed() throws SQLException
+ {
+ return db == null;
+ }
+
+ public String getCatalog() throws SQLException
+ {
+ checkOpen();
+ return null;
+ }
+
+ public void setCatalog(String catalog) throws SQLException
+ {
+ checkOpen();
+ }
+
+ public int getHoldability() throws SQLException
+ {
+ checkOpen();
+ return ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ }
+
+ public void setHoldability(int h) throws SQLException
+ {
+ checkOpen();
+ if (h != ResultSet.CLOSE_CURSORS_AT_COMMIT)
+ throw new SQLException("SQLite only supports CLOSE_CURSORS_AT_COMMIT");
+ }
+
+ public int getTransactionIsolation()
+ {
+ return TRANSACTION_SERIALIZABLE;
+ }
+
+ public void setTransactionIsolation(int level) throws SQLException
+ {
+ if (level != TRANSACTION_SERIALIZABLE)
+ throw new SQLException("SQLite supports only TRANSACTION_SERIALIZABLE");
+ }
+
+ public Map getTypeMap() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ public void setTypeMap(Map<String, Class< ? >> map) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ public boolean isReadOnly() throws SQLException
+ {
+ return false;
+ } // FIXME
+
+ public void setReadOnly(boolean ro) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ public DatabaseMetaData getMetaData()
+ {
+ if (meta == null)
+ meta = new MetaData(this);
+ return meta;
+ }
+
+ public String nativeSQL(String sql)
+ {
+ return sql;
+ }
+
+ public void clearWarnings() throws SQLException
+ {}
+
+ public SQLWarning getWarnings() throws SQLException
+ {
+ return null;
+ }
+
+ // TODO: optimise with direct jni calls for begin/commit/rollback
+ public boolean getAutoCommit() throws SQLException
+ {
+ checkOpen();
+ return autoCommit;
+ }
+
+ public void setAutoCommit(boolean ac) throws SQLException
+ {
+ checkOpen();
+ if (autoCommit == ac)
+ return;
+ autoCommit = ac;
+ db.exec(autoCommit ? "COMMIT;" : "BEGIN DEFERRED;");
+ }
+
+ public void commit() throws SQLException
+ {
+ checkOpen();
+ if (autoCommit)
+ throw new SQLException("database in auto-commit mode");
+ db.exec("COMMIT;");
+ db.exec("BEGIN DEFERRED;");
+ }
+
+ public void rollback() throws SQLException
+ {
+ checkOpen();
+ if (autoCommit)
+ throw new SQLException("database in auto-commit mode");
+ db.exec("ROLLBACK;");
+ db.exec("BEGIN DEFERRED;");
+ }
+
+ public Statement createStatement() throws SQLException
+ {
+ return createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ }
+
+ public Statement createStatement(int rsType, int rsConcurr) throws SQLException
+ {
+ return createStatement(rsType, rsConcurr, ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ }
+
+ public Statement createStatement(int rst, int rsc, int rsh) throws SQLException
+ {
+ checkCursor(rst, rsc, rsh);
+ return new Stmt(this);
+ }
+
+ public CallableStatement prepareCall(String sql) throws SQLException
+ {
+ return prepareCall(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
+ ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ }
+
+ public CallableStatement prepareCall(String sql, int rst, int rsc) throws SQLException
+ {
+ return prepareCall(sql, rst, rsc, ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ }
+
+ public CallableStatement prepareCall(String sql, int rst, int rsc, int rsh) throws SQLException
+ {
+ throw new SQLException("SQLite does not support Stored Procedures");
+ }
+
+ public PreparedStatement prepareStatement(String sql) throws SQLException
+ {
+ return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+ }
+
+ public PreparedStatement prepareStatement(String sql, int autoC) throws SQLException
+ {
+ throw new SQLException("NYI");
+ }
+
+ public PreparedStatement prepareStatement(String sql, int[] colInds) throws SQLException
+ {
+ throw new SQLException("NYI");
+ }
+
+ public PreparedStatement prepareStatement(String sql, String[] colNames) throws SQLException
+ {
+ throw new SQLException("NYI");
+ }
+
+ public PreparedStatement prepareStatement(String sql, int rst, int rsc) throws SQLException
+ {
+ return prepareStatement(sql, rst, rsc, ResultSet.CLOSE_CURSORS_AT_COMMIT);
+ }
+
+ public PreparedStatement prepareStatement(String sql, int rst, int rsc, int rsh) throws SQLException
+ {
+ checkCursor(rst, rsc, rsh);
+ return new PrepStmt(this, sql);
+ }
+
+ // UNUSED FUNCTIONS /////////////////////////////////////////////
+
+ public Savepoint setSavepoint() throws SQLException
+ {
+ throw new SQLException("unsupported by SQLite: savepoints");
+ }
+
+ public Savepoint setSavepoint(String name) throws SQLException
+ {
+ throw new SQLException("unsupported by SQLite: savepoints");
+ }
+
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException
+ {
+ throw new SQLException("unsupported by SQLite: savepoints");
+ }
+
+ public void rollback(Savepoint savepoint) throws SQLException
+ {
+ throw new SQLException("unsupported by SQLite: savepoints");
+ }
+
+ @Override
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public Blob createBlob() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public Clob createClob() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public NClob createNClob() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public SQLXML createSQLXML() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public Properties getClientInfo() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public String getClientInfo(String name) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean isValid(int timeout) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setClientInfo(Properties properties) throws SQLClientInfoException
+ {
+ throw new SQLClientInfoException();
+ }
+
+ @Override
+ public void setClientInfo(String name, String value) throws SQLClientInfoException
+ {
+ throw new SQLClientInfoException();
+ }
+
+ @Override
+ public boolean isWrapperFor(Class< ? > iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.lang.ref.*;
+import java.io.File;
+import java.sql.*;
+import java.util.*;
+
+abstract class DB implements Codes
+{
+ /** database pointer */
+ long pointer = 0;
+
+ /** tracer for statements to avoid unfinalized statements on db close */
+ private Map stmts = new Hashtable();
+
+ // WRAPPER FUNCTIONS ////////////////////////////////////////////
+
+ abstract void open(String filename) throws SQLException;
+ abstract void interrupt() throws SQLException;
+ abstract void busy_timeout(int ms) throws SQLException;
+ abstract String errmsg() throws SQLException;
+ abstract String libversion() throws SQLException;
+ abstract int changes() throws SQLException;
+
+ final synchronized void exec(String sql) throws SQLException {
+ long pointer = 0;
+ try {
+ pointer = prepare(sql);
+ if (step(pointer) == SQLITE_ERROR)
+ throwex();
+ } finally {
+ finalize(pointer);
+ }
+ }
+
+ final synchronized void close() throws SQLException {
+ // finalize any remaining statements before closing db
+ synchronized (stmts) {
+ Iterator i = stmts.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ RS stmt = (RS)((WeakReference)entry.getValue()).get();
+ finalize(((Long)entry.getKey()).longValue());
+ if (stmt != null) {
+ stmt.pointer = 0;
+ stmt.db = null;
+ }
+ i.remove();
+ }
+ }
+
+ // remove memory used by user-defined functions
+ free_functions();
+
+ _close();
+ }
+
+ final synchronized void prepare(RS stmt) throws SQLException {
+ if (stmt.pointer != 0)
+ finalize(stmt);
+ stmt.pointer = prepare(stmt.sql);
+ stmts.put(new Long(stmt.pointer),
+ new WeakReference(stmt));
+ }
+
+ final synchronized int finalize(RS stmt) throws SQLException {
+ if (stmt.pointer == 0) return 0;
+ int rc = SQLITE_ERROR;
+ try {
+ rc = finalize(stmt.pointer);
+ } finally {
+ stmts.remove(new Long(stmt.pointer));
+ stmt.pointer = 0;
+ }
+ return rc;
+ }
+
+ final synchronized int step(RS stmt) throws SQLException {
+ int rc = step(stmt.pointer);
+
+ // deal with goofy interface
+ if (rc == SQLITE_ERROR)
+ rc = reset(stmt.pointer);
+ if (rc == SQLITE_SCHEMA) {
+ prepare(stmt);
+ return step(stmt);
+ }
+ return rc;
+ }
+
+ protected abstract void _close() throws SQLException;
+ protected abstract long prepare(String sql) throws SQLException;
+ protected abstract int finalize(long stmt) throws SQLException;
+ protected abstract int step(long stmt) throws SQLException;
+ protected abstract int reset(long stmt) throws SQLException;
+
+ abstract int clear_bindings(long stmt) throws SQLException; // TODO remove?
+ abstract int bind_parameter_count(long stmt) throws SQLException;
+
+ abstract int column_count (long stmt) throws SQLException;
+ abstract int column_type (long stmt, int col) throws SQLException;
+ abstract String column_decltype (long stmt, int col) throws SQLException;
+ abstract String column_table_name (long stmt, int col) throws SQLException;
+ abstract String column_name (long stmt, int col) throws SQLException;
+ abstract String column_text (long stmt, int col) throws SQLException;
+ abstract byte[] column_blob (long stmt, int col) throws SQLException;
+ abstract double column_double (long stmt, int col) throws SQLException;
+ abstract long column_long (long stmt, int col) throws SQLException;
+ abstract int column_int (long stmt, int col) throws SQLException;
+
+ abstract int bind_null (long stmt, int pos) throws SQLException;
+ abstract int bind_int (long stmt, int pos, int v) throws SQLException;
+ abstract int bind_long (long stmt, int pos, long v) throws SQLException;
+ abstract int bind_double(long stmt, int pos, double v) throws SQLException;
+ abstract int bind_text (long stmt, int pos, String v) throws SQLException;
+ abstract int bind_blob (long stmt, int pos, byte[] v) throws SQLException;
+
+ abstract void result_null (long context) throws SQLException;
+ abstract void result_text (long context, String val) throws SQLException;
+ abstract void result_blob (long context, byte[] val) throws SQLException;
+ abstract void result_double(long context, double val) throws SQLException;
+ abstract void result_long (long context, long val) throws SQLException;
+ abstract void result_int (long context, int val) throws SQLException;
+ abstract void result_error (long context, String err) throws SQLException;
+
+ abstract int value_bytes (Function f, int arg) throws SQLException;
+ abstract String value_text (Function f, int arg) throws SQLException;
+ abstract byte[] value_blob (Function f, int arg) throws SQLException;
+ abstract double value_double(Function f, int arg) throws SQLException;
+ abstract long value_long (Function f, int arg) throws SQLException;
+ abstract int value_int (Function f, int arg) throws SQLException;
+ abstract int value_type (Function f, int arg) throws SQLException;
+
+ abstract int create_function(String name, Function f) throws SQLException;
+ abstract int destroy_function(String name) throws SQLException;
+ abstract void free_functions() throws SQLException;
+
+ /** Provides metadata for the columns of a statement. Returns:
+ * res[col][0] = true if column constrained NOT NULL
+ * res[col][1] = true if column is part of the primary key
+ * res[col][2] = true if column is auto-increment
+ */
+ abstract boolean[][] column_metadata(long stmt) throws SQLException;
+
+
+ // COMPOUND FUNCTIONS ////////////////////////////////////////////
+
+ final synchronized String[] column_names(long stmt) throws SQLException {
+ String[] names = new String[column_count(stmt)];
+ for (int i=0; i < names.length; i++)
+ names[i] = column_name(stmt, i);
+ return names;
+ }
+
+ final synchronized int sqlbind(long stmt, int pos, Object v)
+ throws SQLException {
+ pos++;
+ if (v == null) {
+ return bind_null(stmt, pos);
+ } else if (v instanceof Integer) {
+ return bind_int(stmt, pos, ((Integer)v).intValue());
+ } else if (v instanceof Long) {
+ return bind_long(stmt, pos, ((Long)v).longValue());
+ } else if (v instanceof Double) {
+ return bind_double(stmt, pos, ((Double)v).doubleValue());
+ } else if (v instanceof String) {
+ return bind_text(stmt, pos, (String)v);
+ } else if (v instanceof byte[]) {
+ return bind_blob(stmt, pos, (byte[])v);
+ } else {
+ throw new SQLException("unexpected param type: "+v.getClass());
+ }
+ }
+
+ final synchronized int[] executeBatch(long stmt, int count, Object[] vals)
+ throws SQLException {
+ if (count < 1) throw new SQLException("count (" + count + ") < 1");
+
+ final int params = bind_parameter_count(stmt);
+
+ int rc;
+ int[] changes = new int[count];
+
+ for (int i=0; i < count; i++) {
+ reset(stmt);
+ for (int j=0; j < params; j++)
+ if (sqlbind(stmt, j, vals[(i * params) + j]) != SQLITE_OK)
+ throwex();
+
+ rc = step(stmt);
+ // TODO: handle SQLITE_SCHEMA
+ if (rc != SQLITE_DONE) {
+ reset(stmt);
+ if (rc == SQLITE_ROW) throw new BatchUpdateException(
+ "batch entry "+i+": query returns results", changes);
+ throwex();
+ }
+
+ changes[i] = changes();
+ }
+
+ reset(stmt);
+ return changes;
+ }
+
+ final synchronized boolean execute(RS stmt, Object[] vals)
+ throws SQLException {
+ if (vals != null) {
+ final int params = bind_parameter_count(stmt.pointer);
+ if (params != vals.length)
+ throw new SQLException("assertion failure: param count ("
+ + params + ") != value count (" + vals.length + ")");
+
+ for (int i=0; i < params; i++)
+ if (sqlbind(stmt.pointer, i, vals[i]) != SQLITE_OK) throwex();
+ }
+
+ switch (step(stmt)) {
+ case SQLITE_DONE:
+ reset(stmt.pointer);
+ return false;
+ case SQLITE_ROW: return true;
+ case SQLITE_BUSY: throw new SQLException("database locked");
+ case SQLITE_MISUSE:
+ throw new SQLException(errmsg());
+ //throw new SQLException("jdbc internal consistency error");
+ case SQLITE_SCHEMA:
+ throw new SQLException("jdbc internal consistency error");
+ case SQLITE_INTERNAL: // TODO: be specific
+ case SQLITE_PERM: case SQLITE_ABORT: case SQLITE_NOMEM:
+ case SQLITE_READONLY: case SQLITE_INTERRUPT: case SQLITE_IOERR:
+ case SQLITE_CORRUPT:
+ default:
+ finalize(stmt);
+ throw new SQLException(errmsg());
+ }
+ }
+
+ final synchronized int executeUpdate(RS stmt, Object[] vals)
+ throws SQLException {
+ if (execute(stmt, vals))
+ throw new SQLException("query returns results");
+ reset(stmt.pointer);
+ return changes();
+ }
+
+
+ // HELPER FUNCTIONS /////////////////////////////////////////////
+
+ final void throwex() throws SQLException {
+ throw new SQLException(errmsg());
+ }
+}
--- /dev/null
+package org.sqlite;
+
+import java.sql.*;
+
+/** Provides an interface for creating SQLite user-defined functions.
+ *
+ * <p>A subclass of <tt>org.sqlite.Function</tt> can be registered with
+ * <tt>Function.create()</tt> and called by the name it was given. All
+ * functions must implement <tt>xFunc()</tt>, which is called when SQLite
+ * runs the custom function.</p>
+ *
+ * Eg.
+ *
+ * <pre>
+ * Class.forName("org.sqlite.JDBC");
+ * Connection conn = DriverManager.getConnection("jdbc:sqlite:");
+ *
+ * Function.create(conn, "myFunc", new Function() {
+ * protected void xFunc() {
+ * System.out.println("myFunc called!");
+ * }
+ * });
+ *
+ * conn.createStatement().execute("select myFunc();");
+ * </pre>
+ *
+ * <p>Arguments passed to a custom function can be accessed using the
+ * <tt>protected</tt> functions provided. <tt>args()</tt> returns
+ * the number of arguments passed, while
+ * <tt>value_<type>(int)</tt> returns the value of the specific
+ * argument. Similarly a function can return a value using the
+ * <tt>result(<type>)</tt> function.</p>
+ *
+ * <p>Aggregate functions are not yet supported, but coming soon.</p>
+ *
+ */
+public abstract class Function
+{
+ private Conn conn;
+ private DB db;
+
+ long context = 0; // pointer sqlite3_context*
+ long value = 0; // pointer sqlite3_value**
+ int args = 0;
+
+ /** Registers the given function with the Connection using the
+ * provided name. */
+ public static final void create(Connection conn, String name, Function f)
+ throws SQLException {
+ if (conn == null || !(conn instanceof Conn))
+ throw new SQLException("connection must be to an SQLite db");
+ if (conn.isClosed())
+ throw new SQLException("connection closed");
+
+ f.conn = (Conn)conn;
+ f.db = f.conn.db();
+
+ if (name == null || name.length() > 255)
+ throw new SQLException("invalid function name: '"+name+"'");
+
+ if (f.db.create_function(name, f) != Codes.SQLITE_OK)
+ throw new SQLException("error creating function");
+ }
+
+ /** Removes the named function form the Connection. */
+ public static final void destroy(Connection conn, String name)
+ throws SQLException {
+ if (conn == null || !(conn instanceof Conn))
+ throw new SQLException("connection must be to an SQLite db");
+ ((Conn)conn).db().destroy_function(name);
+ }
+
+
+ /** Called by SQLite as a custom function. Should access arguments
+ * through <tt>value_*(int)</tt>, return results with
+ * <tt>result(*)</tt> and throw errors with <tt>error(String)</tt>. */
+ protected abstract void xFunc() throws SQLException;
+
+
+ /** Returns the number of arguments passed to the function.
+ * Can only be called from <tt>xFunc()</tt>. */
+ protected synchronized final int args()
+ throws SQLException { checkContext(); return args; }
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result(byte[] value)
+ throws SQLException { checkContext(); db.result_blob(context, value); }
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result(double value)
+ throws SQLException { checkContext(); db.result_double(context,value);}
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result(int value)
+ throws SQLException { checkContext(); db.result_int(context, value); }
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result(long value)
+ throws SQLException { checkContext(); db.result_long(context, value); }
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result()
+ throws SQLException { checkContext(); db.result_null(context); }
+
+ /** Called by <tt>xFunc</tt> to return a value. */
+ protected synchronized final void result(String value)
+ throws SQLException { checkContext(); db.result_text(context, value); }
+
+ /** Called by <tt>xFunc</tt> to throw an error. */
+ protected synchronized final void error(String err)
+ throws SQLException { checkContext(); db.result_error(context, err); }
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final int value_bytes(int arg)
+ throws SQLException {checkValue(arg); return db.value_bytes(this,arg);}
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final String value_text(int arg)
+ throws SQLException {checkValue(arg); return db.value_text(this,arg);}
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final byte[] value_blob(int arg)
+ throws SQLException {checkValue(arg); return db.value_blob(this,arg); }
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final double value_double(int arg)
+ throws SQLException {checkValue(arg); return db.value_double(this,arg);}
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final int value_int(int arg)
+ throws SQLException {checkValue(arg); return db.value_int(this, arg); }
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final long value_long(int arg)
+ throws SQLException { checkValue(arg); return db.value_long(this,arg); }
+
+ /** Called by <tt>xFunc</tt> to access the value of an argument. */
+ protected synchronized final int value_type(int arg)
+ throws SQLException {checkValue(arg); return db.value_type(this,arg); }
+
+
+ private void checkContext() throws SQLException {
+ if (conn == null || conn.db() == null || context == 0)
+ throw new SQLException("no context, not allowed to read value");
+ }
+
+ private void checkValue(int arg) throws SQLException {
+ if (conn == null || conn.db() == null || value == 0)
+ throw new SQLException("not in value access state");
+ if (arg >= args)
+ throw new SQLException("arg "+arg+" out bounds [0,"+args+")");
+ }
+
+
+ public static abstract class Aggregate
+ extends Function
+ implements Cloneable
+ {
+ protected final void xFunc() {}
+ protected abstract void xStep() throws SQLException;
+ protected abstract void xFinal() throws SQLException;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.sql.*;
+import java.util.*;
+
+public class JDBC implements Driver
+{
+ private static final String PREFIX = "jdbc:sqlite:";
+
+ static {
+ try {
+ DriverManager.registerDriver(new JDBC());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public int getMajorVersion() { return 1; }
+ public int getMinorVersion() { return 1; }
+
+ public boolean jdbcCompliant() { return false; }
+
+ public boolean acceptsURL(String url) {
+ return url != null && url.toLowerCase().startsWith(PREFIX);
+ }
+
+ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
+ throws SQLException {
+ return new DriverPropertyInfo[] {};
+ }
+
+ public Connection connect(String url, Properties info) throws SQLException {
+ if (!acceptsURL(url)) return null;
+ url = url.trim();
+
+ // if no file name is given use a memory database
+ return new Conn(url, PREFIX.equalsIgnoreCase(url) ?
+ ":memory:" : url.substring(PREFIX.length()));
+ }
+}
--- /dev/null
+package org.sqlite;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.RowIdLifetime;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+
+class MetaData implements DatabaseMetaData
+{
+ private Conn conn;
+ private PreparedStatement getTables = null, getTableTypes = null, getTypeInfo = null, getCrossReference = null,
+ getCatalogs = null, getSchemas = null, getUDTs = null, getColumnsTblName = null, getSuperTypes = null,
+ getSuperTables = null, getTablePrivileges = null, getExportedKeys = null, getProcedures = null,
+ getProcedureColumns = null, getAttributes = null, getBestRowIdentifier = null, getVersionColumns = null,
+ getColumnPrivileges = null;
+
+ /** Used by PrepStmt to save generating a new statement every call. */
+ private PreparedStatement getGeneratedKeys = null;
+
+ MetaData(Conn conn)
+ {
+ this.conn = conn;
+ }
+
+ void checkOpen() throws SQLException
+ {
+ if (conn == null)
+ throw new SQLException("connection closed");
+ }
+
+ synchronized void close() throws SQLException
+ {
+ if (conn == null)
+ return;
+
+ try
+ {
+ if (getTables != null)
+ getTables.close();
+ if (getTableTypes != null)
+ getTableTypes.close();
+ if (getTypeInfo != null)
+ getTypeInfo.close();
+ if (getCrossReference != null)
+ getCrossReference.close();
+ if (getCatalogs != null)
+ getCatalogs.close();
+ if (getSchemas != null)
+ getSchemas.close();
+ if (getUDTs != null)
+ getUDTs.close();
+ if (getColumnsTblName != null)
+ getColumnsTblName.close();
+ if (getSuperTypes != null)
+ getSuperTypes.close();
+ if (getSuperTables != null)
+ getSuperTables.close();
+ if (getTablePrivileges != null)
+ getTablePrivileges.close();
+ if (getExportedKeys != null)
+ getExportedKeys.close();
+ if (getProcedures != null)
+ getProcedures.close();
+ if (getProcedureColumns != null)
+ getProcedureColumns.close();
+ if (getAttributes != null)
+ getAttributes.close();
+ if (getBestRowIdentifier != null)
+ getBestRowIdentifier.close();
+ if (getVersionColumns != null)
+ getVersionColumns.close();
+ if (getColumnPrivileges != null)
+ getColumnPrivileges.close();
+ if (getGeneratedKeys != null)
+ getGeneratedKeys.close();
+
+ getTables = null;
+ getTableTypes = null;
+ getTypeInfo = null;
+ getCrossReference = null;
+ getCatalogs = null;
+ getSchemas = null;
+ getUDTs = null;
+ getColumnsTblName = null;
+ getSuperTypes = null;
+ getSuperTables = null;
+ getTablePrivileges = null;
+ getExportedKeys = null;
+ getProcedures = null;
+ getProcedureColumns = null;
+ getAttributes = null;
+ getBestRowIdentifier = null;
+ getVersionColumns = null;
+ getColumnPrivileges = null;
+ getGeneratedKeys = null;
+ }
+ finally
+ {
+ conn = null;
+ }
+ }
+
+ public Connection getConnection()
+ {
+ return conn;
+ }
+
+ public int getDatabaseMajorVersion()
+ {
+ return 3;
+ }
+
+ public int getDatabaseMinorVersion()
+ {
+ return 0;
+ }
+
+ public int getDriverMajorVersion()
+ {
+ return 1;
+ }
+
+ public int getDriverMinorVersion()
+ {
+ return 1;
+ }
+
+ public int getJDBCMajorVersion()
+ {
+ return 2;
+ }
+
+ public int getJDBCMinorVersion()
+ {
+ return 1;
+ }
+
+ public int getDefaultTransactionIsolation()
+ {
+ return Connection.TRANSACTION_SERIALIZABLE;
+ }
+
+ public int getMaxBinaryLiteralLength()
+ {
+ return 0;
+ }
+
+ public int getMaxCatalogNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxCharLiteralLength()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnsInGroupBy()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnsInIndex()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnsInOrderBy()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnsInSelect()
+ {
+ return 0;
+ }
+
+ public int getMaxColumnsInTable()
+ {
+ return 0;
+ }
+
+ public int getMaxConnections()
+ {
+ return 0;
+ }
+
+ public int getMaxCursorNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxIndexLength()
+ {
+ return 0;
+ }
+
+ public int getMaxProcedureNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxRowSize()
+ {
+ return 0;
+ }
+
+ public int getMaxSchemaNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxStatementLength()
+ {
+ return 0;
+ }
+
+ public int getMaxStatements()
+ {
+ return 0;
+ }
+
+ public int getMaxTableNameLength()
+ {
+ return 0;
+ }
+
+ public int getMaxTablesInSelect()
+ {
+ return 0;
+ }
+
+ public int getMaxUserNameLength()
+ {
+ return 0;
+ }
+
+ public int getResultSetHoldability()
+ {
+ return ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ }
+
+ public int getSQLStateType()
+ {
+ return sqlStateSQL99;
+ }
+
+ public String getDatabaseProductName()
+ {
+ return "SQLite";
+ }
+
+ public String getDatabaseProductVersion() throws SQLException
+ {
+ return conn.libversion();
+ }
+
+ public String getDriverName()
+ {
+ return "SQLiteJDBC";
+ }
+
+ public String getDriverVersion()
+ {
+ return "1";
+ }
+
+ public String getExtraNameCharacters()
+ {
+ return "";
+ }
+
+ public String getCatalogSeparator()
+ {
+ return ".";
+ }
+
+ public String getCatalogTerm()
+ {
+ return "catalog";
+ }
+
+ public String getSchemaTerm()
+ {
+ return "schema";
+ }
+
+ public String getProcedureTerm()
+ {
+ return "not_implemented";
+ }
+
+ public String getSearchStringEscape()
+ {
+ return null;
+ }
+
+ public String getIdentifierQuoteString()
+ {
+ return " ";
+ }
+
+ public String getSQLKeywords()
+ {
+ return "";
+ }
+
+ public String getNumericFunctions()
+ {
+ return "";
+ }
+
+ public String getStringFunctions()
+ {
+ return "";
+ }
+
+ public String getSystemFunctions()
+ {
+ return "";
+ }
+
+ public String getTimeDateFunctions()
+ {
+ return "";
+ }
+
+ public String getURL()
+ {
+ return conn.url();
+ }
+
+ public String getUserName()
+ {
+ return null;
+ }
+
+ public boolean allProceduresAreCallable()
+ {
+ return false;
+ }
+
+ public boolean allTablesAreSelectable()
+ {
+ return true;
+ }
+
+ public boolean dataDefinitionCausesTransactionCommit()
+ {
+ return false;
+ }
+
+ public boolean dataDefinitionIgnoredInTransactions()
+ {
+ return false;
+ }
+
+ public boolean doesMaxRowSizeIncludeBlobs()
+ {
+ return false;
+ }
+
+ public boolean deletesAreDetected(int type)
+ {
+ return false;
+ }
+
+ public boolean insertsAreDetected(int type)
+ {
+ return false;
+ }
+
+ public boolean isCatalogAtStart()
+ {
+ return true;
+ }
+
+ public boolean locatorsUpdateCopy()
+ {
+ return false;
+ }
+
+ public boolean nullPlusNonNullIsNull()
+ {
+ return true;
+ }
+
+ public boolean nullsAreSortedAtEnd()
+ {
+ return !nullsAreSortedAtStart();
+ }
+
+ public boolean nullsAreSortedAtStart()
+ {
+ return true;
+ }
+
+ public boolean nullsAreSortedHigh()
+ {
+ return true;
+ }
+
+ public boolean nullsAreSortedLow()
+ {
+ return !nullsAreSortedHigh();
+ }
+
+ public boolean othersDeletesAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean othersInsertsAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean othersUpdatesAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean ownDeletesAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean ownInsertsAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean ownUpdatesAreVisible(int type)
+ {
+ return false;
+ }
+
+ public boolean storesLowerCaseIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean storesLowerCaseQuotedIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean storesMixedCaseIdentifiers()
+ {
+ return true;
+ }
+
+ public boolean storesMixedCaseQuotedIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean storesUpperCaseIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean storesUpperCaseQuotedIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean supportsAlterTableWithAddColumn()
+ {
+ return false;
+ }
+
+ public boolean supportsAlterTableWithDropColumn()
+ {
+ return false;
+ }
+
+ public boolean supportsANSI92EntryLevelSQL()
+ {
+ return false;
+ }
+
+ public boolean supportsANSI92FullSQL()
+ {
+ return false;
+ }
+
+ public boolean supportsANSI92IntermediateSQL()
+ {
+ return false;
+ }
+
+ public boolean supportsBatchUpdates()
+ {
+ return true;
+ }
+
+ public boolean supportsCatalogsInDataManipulation()
+ {
+ return false;
+ }
+
+ public boolean supportsCatalogsInIndexDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsCatalogsInPrivilegeDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsCatalogsInProcedureCalls()
+ {
+ return false;
+ }
+
+ public boolean supportsCatalogsInTableDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsColumnAliasing()
+ {
+ return true;
+ }
+
+ public boolean supportsConvert()
+ {
+ return false;
+ }
+
+ public boolean supportsConvert(int fromType, int toType)
+ {
+ return false;
+ }
+
+ public boolean supportsCorrelatedSubqueries()
+ {
+ return false;
+ }
+
+ public boolean supportsDataDefinitionAndDataManipulationTransactions()
+ {
+ return true;
+ }
+
+ public boolean supportsDataManipulationTransactionsOnly()
+ {
+ return false;
+ }
+
+ public boolean supportsDifferentTableCorrelationNames()
+ {
+ return false;
+ }
+
+ public boolean supportsExpressionsInOrderBy()
+ {
+ return true;
+ }
+
+ public boolean supportsMinimumSQLGrammar()
+ {
+ return true;
+ }
+
+ public boolean supportsCoreSQLGrammar()
+ {
+ return true;
+ }
+
+ public boolean supportsExtendedSQLGrammar()
+ {
+ return false;
+ }
+
+ public boolean supportsLimitedOuterJoins()
+ {
+ return true;
+ }
+
+ public boolean supportsFullOuterJoins()
+ {
+ return false;
+ }
+
+ public boolean supportsGetGeneratedKeys()
+ {
+ return false;
+ }
+
+ public boolean supportsGroupBy()
+ {
+ return true;
+ }
+
+ public boolean supportsGroupByBeyondSelect()
+ {
+ return false;
+ }
+
+ public boolean supportsGroupByUnrelated()
+ {
+ return false;
+ }
+
+ public boolean supportsIntegrityEnhancementFacility()
+ {
+ return false;
+ }
+
+ public boolean supportsLikeEscapeClause()
+ {
+ return false;
+ }
+
+ public boolean supportsMixedCaseIdentifiers()
+ {
+ return true;
+ }
+
+ public boolean supportsMixedCaseQuotedIdentifiers()
+ {
+ return false;
+ }
+
+ public boolean supportsMultipleOpenResults()
+ {
+ return false;
+ }
+
+ public boolean supportsMultipleResultSets()
+ {
+ return false;
+ }
+
+ public boolean supportsMultipleTransactions()
+ {
+ return true;
+ }
+
+ public boolean supportsNamedParameters()
+ {
+ return true;
+ }
+
+ public boolean supportsNonNullableColumns()
+ {
+ return true;
+ }
+
+ public boolean supportsOpenCursorsAcrossCommit()
+ {
+ return false;
+ }
+
+ public boolean supportsOpenCursorsAcrossRollback()
+ {
+ return false;
+ }
+
+ public boolean supportsOpenStatementsAcrossCommit()
+ {
+ return false;
+ }
+
+ public boolean supportsOpenStatementsAcrossRollback()
+ {
+ return false;
+ }
+
+ public boolean supportsOrderByUnrelated()
+ {
+ return false;
+ }
+
+ public boolean supportsOuterJoins()
+ {
+ return true;
+ }
+
+ public boolean supportsPositionedDelete()
+ {
+ return false;
+ }
+
+ public boolean supportsPositionedUpdate()
+ {
+ return false;
+ }
+
+ public boolean supportsResultSetConcurrency(int t, int c)
+ {
+ return t == ResultSet.TYPE_FORWARD_ONLY && c == ResultSet.CONCUR_READ_ONLY;
+ }
+
+ public boolean supportsResultSetHoldability(int h)
+ {
+ return h == ResultSet.CLOSE_CURSORS_AT_COMMIT;
+ }
+
+ public boolean supportsResultSetType(int t)
+ {
+ return t == ResultSet.TYPE_FORWARD_ONLY;
+ }
+
+ public boolean supportsSavepoints()
+ {
+ return false;
+ }
+
+ public boolean supportsSchemasInDataManipulation()
+ {
+ return false;
+ }
+
+ public boolean supportsSchemasInIndexDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsSchemasInPrivilegeDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsSchemasInProcedureCalls()
+ {
+ return false;
+ }
+
+ public boolean supportsSchemasInTableDefinitions()
+ {
+ return false;
+ }
+
+ public boolean supportsSelectForUpdate()
+ {
+ return false;
+ }
+
+ public boolean supportsStatementPooling()
+ {
+ return false;
+ }
+
+ public boolean supportsStoredProcedures()
+ {
+ return false;
+ }
+
+ public boolean supportsSubqueriesInComparisons()
+ {
+ return false;
+ }
+
+ public boolean supportsSubqueriesInExists()
+ {
+ return true;
+ } // TODO:
+ // check
+
+ public boolean supportsSubqueriesInIns()
+ {
+ return true;
+ } // TODO: check
+
+ public boolean supportsSubqueriesInQuantifieds()
+ {
+ return false;
+ }
+
+ public boolean supportsTableCorrelationNames()
+ {
+ return false;
+ }
+
+ public boolean supportsTransactionIsolationLevel(int level)
+ {
+ return level == Connection.TRANSACTION_SERIALIZABLE;
+ }
+
+ public boolean supportsTransactions()
+ {
+ return true;
+ }
+
+ public boolean supportsUnion()
+ {
+ return true;
+ }
+
+ public boolean supportsUnionAll()
+ {
+ return true;
+ }
+
+ public boolean updatesAreDetected(int type)
+ {
+ return false;
+ }
+
+ public boolean usesLocalFilePerTable()
+ {
+ return false;
+ }
+
+ public boolean usesLocalFiles()
+ {
+ return true;
+ }
+
+ public boolean isReadOnly() throws SQLException
+ {
+ return conn.isReadOnly();
+ }
+
+ public ResultSet getAttributes(String c, String s, String t, String a) throws SQLException
+ {
+ if (getAttributes == null)
+ getAttributes = conn.prepareStatement("select " + "null as TYPE_CAT, " + "null as TYPE_SCHEM, "
+ + "null as TYPE_NAME, " + "null as ATTR_NAME, " + "null as DATA_TYPE, "
+ + "null as ATTR_TYPE_NAME, " + "null as ATTR_SIZE, " + "null as DECIMAL_DIGITS, "
+ + "null as NUM_PREC_RADIX, " + "null as NULLABLE, " + "null as REMARKS, " + "null as ATTR_DEF, "
+ + "null as SQL_DATA_TYPE, " + "null as SQL_DATETIME_SUB, " + "null as CHAR_OCTET_LENGTH, "
+ + "null as ORDINAL_POSITION, " + "null as IS_NULLABLE, " + "null as SCOPE_CATALOG, "
+ + "null as SCOPE_SCHEMA, " + "null as SCOPE_TABLE, " + "null as SOURCE_DATA_TYPE limit 0;");
+ return getAttributes.executeQuery();
+ }
+
+ public ResultSet getBestRowIdentifier(String c, String s, String t, int scope, boolean n) throws SQLException
+ {
+ if (getBestRowIdentifier == null)
+ getBestRowIdentifier = conn.prepareStatement("select " + "null as SCOPE, " + "null as COLUMN_NAME, "
+ + "null as DATA_TYPE, " + "null as TYPE_NAME, " + "null as COLUMN_SIZE, "
+ + "null as BUFFER_LENGTH, " + "null as DECIMAL_DIGITS, " + "null as PSEUDO_COLUMN limit 0;");
+ return getBestRowIdentifier.executeQuery();
+ }
+
+ public ResultSet getColumnPrivileges(String c, String s, String t, String colPat) throws SQLException
+ {
+ if (getColumnPrivileges == null)
+ getColumnPrivileges = conn.prepareStatement("select " + "null as TABLE_CAT, " + "null as TABLE_SCHEM, "
+ + "null as TABLE_NAME, " + "null as COLUMN_NAME, " + "null as GRANTOR, " + "null as GRANTEE, "
+ + "null as PRIVILEGE, " + "null as IS_GRANTABLE limit 0;");
+ return getColumnPrivileges.executeQuery();
+ }
+
+ public ResultSet getColumns(String c, String s, String tbl, String colPat) throws SQLException
+ {
+ Statement stat = conn.createStatement();
+ ResultSet rs;
+ String sql;
+
+ checkOpen();
+
+ if (getColumnsTblName == null)
+ getColumnsTblName = conn.prepareStatement("select tbl_name from sqlite_master where tbl_name like ?;");
+
+ // determine exact table name
+ getColumnsTblName.setString(1, tbl);
+ rs = getColumnsTblName.executeQuery();
+ if (!rs.next())
+ return null;
+ tbl = rs.getString(1);
+ rs.close();
+
+ sql = "select " + "null as TABLE_CAT, " + "null as TABLE_SCHEM, " + "'" + escape(tbl) + "' as TABLE_NAME, "
+ + "cn as COLUMN_NAME, " + "-1 as DATA_TYPE, " + "tn as TYPE_NAME, " + "2000000000 as COLUMN_SIZE, "
+ + "2000000000 as BUFFER_LENGTH, " + "10 as DECIMAL_DIGITS, " + "10 as NUM_PREC_RADIX, "
+ + "colnullable as NULLABLE, " + "null as REMARKS, " + "null as COLUMN_DEF, "
+ + "0 as SQL_DATA_TYPE, " + "0 as SQL_DATETIME_SUB, " + "2000000000 as CHAR_OCTET_LENGTH, "
+ + "ordpos as ORDINAL_POSITION, " + "(case colnullable when 0 then 'N' when 1 then 'Y' else '' end)"
+ + " as IS_NULLABLE, " + "null as SCOPE_CATLOG, " + "null as SCOPE_SCHEMA, "
+ + "null as SCOPE_TABLE, " + "null as SOURCE_DATA_TYPE from (";
+
+ // the command "pragma table_info('tablename')" does not embed
+ // like a normal select statement so we must extract the information
+ // and then build a resultset from unioned select statements
+ rs = stat.executeQuery("pragma table_info ('" + escape(tbl) + "');");
+
+ boolean colFound = false;
+ for (int i = 0; rs.next(); i++)
+ {
+ String colName = rs.getString(2);
+ String colType = rs.getString(3);
+ String colNotNull = rs.getString(4);
+
+ int colNullable = 2;
+ if (colType == null)
+ colType = "TEXT";
+ if (colNotNull != null)
+ colNullable = colNotNull.equals("0") ? 1 : 0;
+ if (colFound)
+ sql += " union all ";
+ colFound = true;
+
+ sql += "select " + i + " as ordpos, " + colNullable + " as colnullable, '" + escape(colName) + "' as cn, '"
+ + escape(colType) + "' as tn";
+
+ if (colPat != null)
+ sql += " where upper(cn) like upper('" + escape(colPat) + "')";
+ }
+ sql += colFound ? ");" : "select null as ordpos, null as colnullable, " + "null as cn, null as tn) limit 0;";
+ rs.close();
+
+ return stat.executeQuery(sql);
+ }
+
+ public ResultSet getCrossReference(String pc, String ps, String pt, String fc, String fs, String ft)
+ throws SQLException
+ {
+ if (getCrossReference == null)
+ getCrossReference = conn.prepareStatement("select " + "null as PKTABLE_CAT, " + "null as PKTABLE_SCHEM, "
+ + "null as PKTABLE_NAME, " + "null as PKCOLUMN_NAME, " + "null as FKTABLE_CAT, "
+ + "null as FKTABLE_SCHEM, " + "null as FKTABLE_NAME, " + "null as FKCOLUMN_NAME, "
+ + "null as KEY_SEQ, " + "null as UPDATE_RULE, " + "null as DELETE_RULE, " + "null as FK_NAME, "
+ + "null as PK_NAME, " + "null as DEFERRABILITY " + "limit 0;");
+ getCrossReference.clearParameters();
+ return getCrossReference.executeQuery();
+ }
+
+ public ResultSet getSchemas() throws SQLException
+ {
+ if (getSchemas == null)
+ getSchemas = conn.prepareStatement("select " + "null as TABLE_SCHEM, " + "null as TABLE_CATALOG "
+ + "limit 0;");
+ getSchemas.clearParameters();
+ return getSchemas.executeQuery();
+ }
+
+ public ResultSet getCatalogs() throws SQLException
+ {
+ if (getCatalogs == null)
+ getCatalogs = conn.prepareStatement("select null as TABLE_CAT limit 0;");
+ getCatalogs.clearParameters();
+ return getCatalogs.executeQuery();
+ }
+
+ public ResultSet getPrimaryKeys(String c, String s, String table) throws SQLException
+ {
+ String sql;
+ ResultSet rs;
+ Statement stat = conn.createStatement();
+
+ rs = stat.executeQuery("pragma table_info('" + escape(table) + "');");
+
+ sql = "select " + "null as TABLE_CAT, " + "null as TABLE_SCHEM, " + "'" + escape(table) + "' as TABLE_NAME, "
+ + "cn as COLUMN_NAME, " + "0 as KEY_SEQ, " + "null as PK_NAME from (";
+
+ int i;
+ for (i = 0; rs.next(); i++)
+ {
+ String colName = rs.getString(2);
+
+ if (!rs.getBoolean(6))
+ {
+ i--;
+ continue;
+ }
+ if (i > 0)
+ sql += " union all ";
+
+ sql += "select '" + escape(colName) + "' as cn";
+ }
+ sql += i == 0 ? "select null as cn) limit 0;" : ");";
+ rs.close();
+
+ return stat.executeQuery(sql);
+ }
+
+ public ResultSet getExportedKeys(String c, String s, String t) throws SQLException
+ {
+ if (getExportedKeys == null)
+ getExportedKeys = conn.prepareStatement("select " + "null as PKTABLE_CAT, " + "null as PKTABLE_SCHEM, "
+ + "null as PKTABLE_NAME, " + "null as PKCOLUMN_NAME, " + "null as FKTABLE_CAT, "
+ + "null as FKTABLE_SCHEM, " + "null as FKTABLE_NAME, " + "null as FKCOLUMN_NAME, "
+ + "null as KEY_SEQ, " + "null as UPDATE_RULE, " + "null as DELETE_RULE, " + "null as FK_NAME, "
+ + "null as PK_NAME, " + "null as DEFERRABILITY limit 0;");
+ return getExportedKeys.executeQuery();
+ }
+
+ public ResultSet getImportedKeys(String c, String s, String t) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ public ResultSet getIndexInfo(String c, String s, String t, boolean u, boolean approximate) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ public ResultSet getProcedureColumns(String c, String s, String p, String colPat) throws SQLException
+ {
+ if (getProcedures == null)
+ getProcedureColumns = conn.prepareStatement("select " + "null as PROCEDURE_CAT, "
+ + "null as PROCEDURE_SCHEM, " + "null as PROCEDURE_NAME, " + "null as COLUMN_NAME, "
+ + "null as COLUMN_TYPE, " + "null as DATA_TYPE, " + "null as TYPE_NAME, " + "null as PRECISION, "
+ + "null as LENGTH, " + "null as SCALE, " + "null as RADIX, " + "null as NULLABLE, "
+ + "null as REMARKS limit 0;");
+ return getProcedureColumns.executeQuery();
+
+ }
+
+ public ResultSet getProcedures(String c, String s, String p) throws SQLException
+ {
+ if (getProcedures == null)
+ getProcedures = conn.prepareStatement("select " + "null as PROCEDURE_CAT, " + "null as PROCEDURE_SCHEM, "
+ + "null as PROCEDURE_NAME, " + "null as UNDEF1, " + "null as UNDEF2, " + "null as UNDEF3, "
+ + "null as REMARKS, " + "null as PROCEDURE_TYPE limit 0;");
+ return getProcedures.executeQuery();
+ }
+
+ public ResultSet getSuperTables(String c, String s, String t) throws SQLException
+ {
+ if (getSuperTables == null)
+ getSuperTables = conn.prepareStatement("select " + "null as TABLE_CAT, " + "null as TABLE_SCHEM, "
+ + "null as TABLE_NAME, " + "null as SUPERTABLE_NAME limit 0;");
+ return getSuperTables.executeQuery();
+ }
+
+ public ResultSet getSuperTypes(String c, String s, String t) throws SQLException
+ {
+ if (getSuperTypes == null)
+ getSuperTypes = conn.prepareStatement("select " + "null as TYPE_CAT, " + "null as TYPE_SCHEM, "
+ + "null as TYPE_NAME, " + "null as SUPERTYPE_CAT, " + "null as SUPERTYPE_SCHEM, "
+ + "null as SUPERTYPE_NAME limit 0;");
+ return getSuperTypes.executeQuery();
+ }
+
+ public ResultSet getTablePrivileges(String c, String s, String t) throws SQLException
+ {
+ if (getTablePrivileges == null)
+ getTablePrivileges = conn.prepareStatement("select " + "null as TABLE_CAT, " + "null as TABLE_SCHEM, "
+ + "null as TABLE_NAME, " + "null as GRANTOR, " + "null as GRANTEE, " + "null as PRIVILEGE, "
+ + "null as IS_GRANTABLE limit 0;");
+ return getTablePrivileges.executeQuery();
+ }
+
+ public synchronized ResultSet getTables(String c, String s, String t, String[] types) throws SQLException
+ {
+ checkOpen();
+
+ t = (t == null || "".equals(t)) ? "%" : t.toUpperCase();
+
+ String sql = "select" + " null as TABLE_CAT," + " null as TABLE_SCHEM," + " upper(name) as TABLE_NAME,"
+ + " upper(type) as TABLE_TYPE," + " null as REMARKS," + " null as TYPE_CAT," + " null as TYPE_SCHEM,"
+ + " null as TYPE_NAME," + " null as SELF_REFERENCING_COL_NAME," + " null as REF_GENERATION"
+ + " from (select name, type from sqlite_master union all"
+ + " select name, type from sqlite_temp_master)" + " where TABLE_NAME like '" + escape(t) + "'";
+
+ if (types != null)
+ {
+ sql += " and TABLE_TYPE in (";
+ for (int i = 0; i < types.length; i++)
+ {
+ if (i > 0)
+ sql += ", ";
+ sql += "'" + types[i].toUpperCase() + "'";
+ }
+ sql += ")";
+ }
+
+ sql += ";";
+
+ return conn.createStatement().executeQuery(sql);
+ }
+
+ public ResultSet getTableTypes() throws SQLException
+ {
+ checkOpen();
+ if (getTableTypes == null)
+ getTableTypes = conn.prepareStatement("select 'TABLE' as TABLE_TYPE"
+ + " union select 'VIEW' as TABLE_TYPE;");
+ getTableTypes.clearParameters();
+ return getTableTypes.executeQuery();
+ }
+
+ public ResultSet getTypeInfo() throws SQLException
+ {
+ if (getTypeInfo == null)
+ {
+ getTypeInfo = conn.prepareStatement("select " + "tn as TYPE_NAME, " + "dt as DATA_TYPE, "
+ + "0 as PRECISION, " + "null as LITERAL_PREFIX, " + "null as LITERAL_SUFFIX, "
+ + "null as CREATE_PARAMS, "
+ + typeNullable
+ + " as NULLABLE, "
+ + "1 as CASE_SENSITIVE, "
+ + typeSearchable
+ + " as SEARCHABLE, "
+ + "0 as UNSIGNED_ATTRIBUTE, "
+ + "0 as FIXED_PREC_SCALE, "
+ + "0 as AUTO_INCREMENT, "
+ + "null as LOCAL_TYPE_NAME, "
+ + "0 as MINIMUM_SCALE, "
+ + "0 as MAXIMUM_SCALE, "
+ + "0 as SQL_DATA_TYPE, "
+ + "0 as SQL_DATETIME_SUB, "
+ + "10 as NUM_PREC_RADIX from ("
+ + " select 'BLOB' as tn, "
+ + Types.BLOB
+ + " as dt union"
+ + " select 'NULL' as tn, "
+ + Types.NULL
+ + " as dt union"
+ + " select 'REAL' as tn, "
+ + Types.REAL
+ + " as dt union"
+ + " select 'TEXT' as tn, "
+ + Types.VARCHAR
+ + " as dt union"
+ + " select 'INTEGER' as tn, "
+ + Types.INTEGER + " as dt" + ") order by TYPE_NAME;");
+ }
+
+ getTypeInfo.clearParameters();
+ return getTypeInfo.executeQuery();
+ }
+
+ public ResultSet getUDTs(String c, String s, String t, int[] types) throws SQLException
+ {
+ if (getUDTs == null)
+ getUDTs = conn.prepareStatement("select " + "null as TYPE_CAT, " + "null as TYPE_SCHEM, "
+ + "null as TYPE_NAME, " + "null as CLASS_NAME, " + "null as DATA_TYPE, " + "null as REMARKS, "
+ + "null as BASE_TYPE " + "limit 0;");
+
+ getUDTs.clearParameters();
+ return getUDTs.executeQuery();
+ }
+
+ public ResultSet getVersionColumns(String c, String s, String t) throws SQLException
+ {
+ if (getVersionColumns == null)
+ getVersionColumns = conn.prepareStatement("select " + "null as SCOPE, " + "null as COLUMN_NAME, "
+ + "null as DATA_TYPE, " + "null as TYPE_NAME, " + "null as COLUMN_SIZE, "
+ + "null as BUFFER_LENGTH, " + "null as DECIMAL_DIGITS, " + "null as PSEUDO_COLUMN limit 0;");
+ return getVersionColumns.executeQuery();
+ }
+
+ ResultSet getGeneratedKeys() throws SQLException
+ {
+ if (getGeneratedKeys == null)
+ getGeneratedKeys = conn.prepareStatement("select last_insert_rowid();");
+ return getGeneratedKeys.executeQuery();
+ }
+
+ /** Replace all instances of ' with '' */
+ private String escape(final String val)
+ {
+ // TODO: this function is ugly, pass this work off to SQLite, then we
+ // don't have to worry about Unicode 4, other characters needing
+ // escaping, etc.
+ int len = val.length();
+ StringBuffer buf = new StringBuffer(len);
+ for (int i = 0; i < len; i++)
+ {
+ if (val.charAt(i) == '\'')
+ buf.append('\'');
+ buf.append(val.charAt(i));
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public boolean autoCommitFailureClosesAllResultSets() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public ResultSet getClientInfoProperties() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern,
+ String columnNamePattern) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public RowIdLifetime getRowIdLifetime() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean isWrapperFor(Class< ? > iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "NativeDB.h"
+#include "sqlite3.h"
+
+static jclass dbclass = 0;
+static jclass fclass = 0;
+static jclass aclass = 0;
+
+static void * toref(jlong value)
+{
+ jvalue ret;
+ ret.j = value;
+ return (void *) ret.l;
+}
+
+static jlong fromref(void * value)
+{
+ jvalue ret;
+ ret.l = value;
+ return ret.j;
+}
+
+static void throwex(JNIEnv *env, jobject this)
+{
+ static jmethodID mth_throwex = 0;
+
+ if (!mth_throwex)
+ mth_throwex = (*env)->GetMethodID(env, dbclass, "throwex", "()V");
+
+ (*env)->CallVoidMethod(env, this, mth_throwex);
+}
+
+static void throwexmsg(JNIEnv *env, const char *str)
+{
+ static jmethodID mth_throwexmsg = 0;
+
+ if (!mth_throwexmsg) mth_throwexmsg = (*env)->GetStaticMethodID(
+ env, dbclass, "throwex", "(Ljava/lang/String;)V");
+
+ (*env)->CallStaticVoidMethod(env, dbclass, mth_throwexmsg,
+ (*env)->NewStringUTF(env, str));
+}
+
+static sqlite3 * gethandle(JNIEnv *env, jobject this)
+{
+ static jfieldID pointer = 0;
+ if (!pointer) pointer = (*env)->GetFieldID(env, dbclass, "pointer", "J");
+
+ return (sqlite3 *)toref((*env)->GetLongField(env, this, pointer));
+}
+
+static void sethandle(JNIEnv *env, jobject this, sqlite3 * ref)
+{
+ static jfieldID pointer = 0;
+ if (!pointer) pointer = (*env)->GetFieldID(env, dbclass, "pointer", "J");
+
+ (*env)->SetLongField(env, this, pointer, fromref(ref));
+}
+
+/* Returns number of 16-bit blocks in UTF-16 string, not including null. */
+static jsize jstrlen(const jchar *str)
+{
+ const jchar *s;
+ for (s = str; *s; s++);
+ return (jsize)(s - str);
+}
+
+
+// User Defined Function SUPPORT ////////////////////////////////////
+
+struct UDFData {
+ JavaVM *vm;
+ jobject func;
+ struct UDFData *next; // linked list of all UDFData instances
+};
+
+/* Returns the sqlite3_value for the given arg of the given function.
+ * If 0 is returned, an exception has been thrown to report the reason. */
+static sqlite3_value * tovalue(JNIEnv *env, jobject function, jint arg)
+{
+ jlong value_pntr = 0;
+ jint numArgs = 0;
+ static jfieldID func_value = 0,
+ func_args = 0;
+
+ if (!func_value || !func_args) {
+ func_value = (*env)->GetFieldID(env, fclass, "value", "J");
+ func_args = (*env)->GetFieldID(env, fclass, "args", "I");
+ }
+
+ // check we have any business being here
+ if (arg < 0) { throwexmsg(env, "negative arg out of range"); return 0; }
+ if (!function) { throwexmsg(env, "inconstent function"); return 0; }
+
+ value_pntr = (*env)->GetLongField(env, function, func_value);
+ numArgs = (*env)->GetIntField(env, function, func_args);
+
+ if (value_pntr == 0) { throwexmsg(env, "no current value"); return 0; }
+ if (arg >= numArgs) { throwexmsg(env, "arg out of range"); return 0; }
+
+ return ((sqlite3_value**)toref(value_pntr))[arg];
+}
+
+/* called if an exception occured processing xFunc */
+static void xFunc_error(sqlite3_context *context, JNIEnv *env)
+{
+ const char *strmsg = 0;
+ jstring msg = 0;
+ jint msgsize = 0;
+
+ jclass exclass = 0;
+ static jmethodID exp_msg = 0;
+ jthrowable ex = (*env)->ExceptionOccurred(env);
+
+ (*env)->ExceptionClear(env);
+
+ if (!exp_msg) {
+ exclass = (*env)->FindClass(env, "java/lang/Throwable");
+ exp_msg = (*env)->GetMethodID(
+ env, exclass, "toString", "()Ljava/lang/String;");
+ }
+
+ msg = (jstring)(*env)->CallObjectMethod(env, ex, exp_msg);
+ if (!msg) { sqlite3_result_error(context, "unknown error", 13); return; }
+
+ msgsize = (*env)->GetStringUTFLength(env, msg);
+ strmsg = (*env)->GetStringUTFChars(env, msg, 0);
+ assert(strmsg); // out-of-memory
+
+ sqlite3_result_error(context, strmsg, msgsize);
+
+ (*env)->ReleaseStringUTFChars(env, msg, strmsg);
+}
+
+/* used to call xFunc, xStep and xFinal */
+static xCall(
+ sqlite3_context *context,
+ int args,
+ sqlite3_value** value,
+ jobject func,
+ jmethodID method)
+{
+ static jfieldID fld_context = 0,
+ fld_value = 0,
+ fld_args = 0;
+ JNIEnv *env = 0;
+ struct UDFData *udf = 0;
+
+ udf = (struct UDFData*)sqlite3_user_data(context);
+ assert(udf);
+ (*udf->vm)->AttachCurrentThread(udf->vm, (void **)&env, 0);
+ if (!func) func = udf->func;
+
+ if (!fld_context || !fld_value || !fld_args) {
+ fld_context = (*env)->GetFieldID(env, fclass, "context", "J");
+ fld_value = (*env)->GetFieldID(env, fclass, "value", "J");
+ fld_args = (*env)->GetFieldID(env, fclass, "args", "I");
+ }
+
+ (*env)->SetLongField(env, func, fld_context, fromref(context));
+ (*env)->SetLongField(env, func, fld_value, value ? fromref(value) : 0);
+ (*env)->SetIntField(env, func, fld_args, args);
+
+ (*env)->CallVoidMethod(env, func, method);
+
+ (*env)->SetLongField(env, func, fld_context, 0);
+ (*env)->SetLongField(env, func, fld_value, 0);
+ (*env)->SetIntField(env, func, fld_args, 0);
+
+ // check if xFunc threw an Exception
+ if ((*env)->ExceptionCheck(env)) xFunc_error(context, env);
+}
+
+
+void xFunc(sqlite3_context *context, int args, sqlite3_value** value)
+{
+ static jmethodID mth = 0;
+ if (!mth) {
+ JNIEnv *env;
+ struct UDFData *udf = (struct UDFData*)sqlite3_user_data(context);
+ (*udf->vm)->AttachCurrentThread(udf->vm, (void **)&env, 0);
+ mth = (*env)->GetMethodID(env, fclass, "xFunc", "()V");
+ }
+ xCall(context, args, value, 0, mth);
+}
+
+void xStep(sqlite3_context *context, int args, sqlite3_value** value)
+{
+ JNIEnv *env;
+ struct UDFData *udf;
+ jobject *func = 0;
+ static jmethodID mth = 0;
+ static jmethodID clone = 0;
+
+ if (!mth || !clone) {
+ udf = (struct UDFData*)sqlite3_user_data(context);
+ (*udf->vm)->AttachCurrentThread(udf->vm, (void **)&env, 0);
+
+ mth = (*env)->GetMethodID(env, aclass, "xStep", "()V");
+ clone = (*env)->GetMethodID(env, aclass, "clone",
+ "()Ljava/lang/Object;");
+ }
+
+ // clone the Function.Aggregate instance and store a pointer
+ // in SQLite's aggregate_context (clean up in xFinal)
+ func = sqlite3_aggregate_context(context, sizeof(jobject));
+ if (!*func) {
+ udf = (struct UDFData*)sqlite3_user_data(context);
+ (*udf->vm)->AttachCurrentThread(udf->vm, (void **)&env, 0);
+
+ *func = (*env)->CallObjectMethod(env, udf->func, clone);
+ *func = (*env)->NewGlobalRef(env, *func);
+ }
+
+ xCall(context, args, value, *func, mth);
+}
+
+void xFinal(sqlite3_context *context)
+{
+ JNIEnv *env = 0;
+ struct UDFData *udf = 0;
+ jobject *func = 0;
+ static jmethodID mth = 0;
+
+ udf = (struct UDFData*)sqlite3_user_data(context);
+ (*udf->vm)->AttachCurrentThread(udf->vm, (void **)&env, 0);
+
+ if (!mth) mth = (*env)->GetMethodID(env, aclass, "xFinal", "()V");
+
+ func = sqlite3_aggregate_context(context, sizeof(jobject));
+ assert(*func); // disaster
+
+ xCall(context, 0, 0, *func, mth);
+
+ // clean up Function.Aggregate instance
+ (*env)->DeleteGlobalRef(env, *func);
+}
+
+
+// INITIALISATION ///////////////////////////////////////////////////
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ JNIEnv* env = 0;
+
+ if (JNI_OK != (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2))
+ return JNI_ERR;
+
+ dbclass = (*env)->FindClass(env, "org/sqlite/NativeDB");
+ if (!dbclass) return JNI_ERR;
+ dbclass = (*env)->NewGlobalRef(env, dbclass);
+
+ fclass = (*env)->FindClass(env, "org/sqlite/Function");
+ if (!fclass) return JNI_ERR;
+ fclass = (*env)->NewGlobalRef(env, fclass);
+
+ aclass = (*env)->FindClass(env, "org/sqlite/Function$Aggregate");
+ if (!aclass) return JNI_ERR;
+ aclass = (*env)->NewGlobalRef(env, aclass);
+
+ return JNI_VERSION_1_2;
+}
+
+
+// WRAPPERS for sqlite_* functions //////////////////////////////////
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_open(
+ JNIEnv *env, jobject this, jstring file)
+{
+ int ret;
+ sqlite3 *db = gethandle(env, this);
+ const char *str;
+
+ if (db) {
+ throwexmsg(env, "DB already open");
+ sqlite3_close(db);
+ return;
+ }
+
+ str = (*env)->GetStringUTFChars(env, file, 0);
+ if (sqlite3_open(str, &db)) {
+ throwex(env, this);
+ sqlite3_close(db);
+ return;
+ }
+ (*env)->ReleaseStringUTFChars(env, file, str);
+
+ sethandle(env, this, db);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB__1close(
+ JNIEnv *env, jobject this)
+{
+ if (sqlite3_close(gethandle(env, this)) != SQLITE_OK)
+ throwex(env, this);
+ sethandle(env, this, 0);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_interrupt(JNIEnv *env, jobject this)
+{
+ sqlite3_interrupt(gethandle(env, this));
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_busy_1timeout(
+ JNIEnv *env, jobject this, jint ms)
+{
+ sqlite3_busy_timeout(gethandle(env, this), ms);
+}
+
+JNIEXPORT jlong JNICALL Java_org_sqlite_NativeDB_prepare(
+ JNIEnv *env, jobject this, jstring sql)
+{
+ sqlite3* db = gethandle(env, this);
+ sqlite3_stmt* stmt;
+
+ const char *strsql = (*env)->GetStringUTFChars(env, sql, 0);
+ int status = sqlite3_prepare(db, strsql, -1, &stmt, 0);
+ (*env)->ReleaseStringUTFChars(env, sql, strsql);
+
+ if (status != SQLITE_OK) {
+ throwex(env, this);
+ return fromref(0);
+ }
+ return fromref(stmt);
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_errmsg(JNIEnv *env, jobject this)
+{
+ return (*env)->NewStringUTF(env, sqlite3_errmsg(gethandle(env, this)));
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_libversion(
+ JNIEnv *env, jobject this)
+{
+ return (*env)->NewStringUTF(env, sqlite3_libversion());
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_changes(
+ JNIEnv *env, jobject this)
+{
+ return sqlite3_changes(gethandle(env, this));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_finalize(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ return sqlite3_finalize(toref(stmt));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_step(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ return sqlite3_step(toref(stmt));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_reset(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ return sqlite3_reset(toref(stmt));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_clear_1bindings(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ int i;
+ int count = sqlite3_bind_parameter_count(toref(stmt));
+ jint rc = SQLITE_OK;
+ for(i=1; rc==SQLITE_OK && i <= count; i++) {
+ rc = sqlite3_bind_null(toref(stmt), i);
+ }
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1parameter_1count(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ return sqlite3_bind_parameter_count(toref(stmt));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_column_1count(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ return sqlite3_column_count(toref(stmt));
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_column_1type(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ return sqlite3_column_type(toref(stmt), col);
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_column_1decltype(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ const char *str = sqlite3_column_decltype(toref(stmt), col);
+ return (*env)->NewStringUTF(env, str);
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_column_1table_1name(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ const void *str = sqlite3_column_table_name16(toref(stmt), col);
+ return str ? (*env)->NewString(env, str, jstrlen(str)) : NULL;
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_column_1name(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ const void *str = sqlite3_column_name16(toref(stmt), col);
+ return str ? (*env)->NewString(env, str, jstrlen(str)) : NULL;
+}
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_column_1text(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ return (*env)->NewStringUTF(
+ env, (const char*)sqlite3_column_text(toref(stmt), col));
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_NativeDB_column_1blob(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ jsize length;
+ jbyteArray jBlob;
+ jbyte *a;
+ const void *blob = sqlite3_column_blob(toref(stmt), col);
+ if (!blob) return NULL;
+
+ length = sqlite3_column_bytes(toref(stmt), col);
+ jBlob = (*env)->NewByteArray(env, length);
+ assert(jBlob); // out-of-memory
+
+ a = (*env)->GetPrimitiveArrayCritical(env, jBlob, 0);
+ memcpy(a, blob, length);
+ (*env)->ReleasePrimitiveArrayCritical(env, jBlob, a, 0);
+
+ return jBlob;
+}
+
+JNIEXPORT jdouble JNICALL Java_org_sqlite_NativeDB_column_1double(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ return sqlite3_column_double(toref(stmt), col);
+}
+
+JNIEXPORT jlong JNICALL Java_org_sqlite_NativeDB_column_1long(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ return sqlite3_column_int64(toref(stmt), col);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_column_1int(
+ JNIEnv *env, jobject this, jlong stmt, jint col)
+{
+ return sqlite3_column_int(toref(stmt), col);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1null(
+ JNIEnv *env, jobject this, jlong stmt, jint pos)
+{
+ return sqlite3_bind_null(toref(stmt), pos);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1int(
+ JNIEnv *env, jobject this, jlong stmt, jint pos, jint v)
+{
+ return sqlite3_bind_int(toref(stmt), pos, v);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1long(
+ JNIEnv *env, jobject this, jlong stmt, jint pos, jlong v)
+{
+ return sqlite3_bind_int64(toref(stmt), pos, v);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1double(
+ JNIEnv *env, jobject this, jlong stmt, jint pos, jdouble v)
+{
+ return sqlite3_bind_double(toref(stmt), pos, v);
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1text(
+ JNIEnv *env, jobject this, jlong stmt, jint pos, jstring v)
+{
+ const char *chars = (*env)->GetStringUTFChars(env, v, 0);
+ int rc = sqlite3_bind_text(toref(stmt), pos, chars, -1, SQLITE_TRANSIENT);
+ (*env)->ReleaseStringUTFChars(env, v, chars);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_bind_1blob(
+ JNIEnv *env, jobject this, jlong stmt, jint pos, jbyteArray v)
+{
+ jint rc;
+ void *a;
+ jsize size = (*env)->GetArrayLength(env, v);
+ assert(a = (*env)->GetPrimitiveArrayCritical(env, v, 0));
+ rc = sqlite3_bind_blob(toref(stmt), pos, a, size, SQLITE_TRANSIENT);
+ (*env)->ReleasePrimitiveArrayCritical(env, v, a, JNI_ABORT);
+ return rc;
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1null(
+ JNIEnv *env, jobject this, jlong context)
+{
+ sqlite3_result_null(toref(context));
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1text(
+ JNIEnv *env, jobject this, jlong context, jstring value)
+{
+ const jchar *str;
+ jsize size;
+
+ if (value == NULL) { sqlite3_result_null(toref(context)); return; }
+ size = (*env)->GetStringLength(env, value) * 2;
+
+ str = (*env)->GetStringCritical(env, value, 0);
+ assert(str); // out-of-memory
+ sqlite3_result_text16(toref(context), str, size, SQLITE_TRANSIENT);
+ (*env)->ReleaseStringCritical(env, value, str);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1blob(
+ JNIEnv *env, jobject this, jlong context, jobject value)
+{
+ jbyte *bytes;
+ jsize size;
+
+ if (value == NULL) { sqlite3_result_null(toref(context)); return; }
+ size = (*env)->GetArrayLength(env, value);
+
+ // be careful with *Critical
+ bytes = (*env)->GetPrimitiveArrayCritical(env, value, 0);
+ assert(bytes); // out-of-memory
+ sqlite3_result_blob(toref(context), bytes, size, SQLITE_TRANSIENT);
+ (*env)->ReleasePrimitiveArrayCritical(env, value, bytes, JNI_ABORT);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1double(
+ JNIEnv *env, jobject this, jlong context, jdouble value)
+{
+ sqlite3_result_double(toref(context), value);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1long(
+ JNIEnv *env, jobject this, jlong context, jlong value)
+{
+ sqlite3_result_int64(toref(context), value);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_result_1int(
+ JNIEnv *env, jobject this, jlong context, jint value)
+{
+ sqlite3_result_int(toref(context), value);
+}
+
+
+
+
+JNIEXPORT jstring JNICALL Java_org_sqlite_NativeDB_value_1text(
+ JNIEnv *env, jobject this, jobject f, jint arg)
+{
+ jint length = 0;
+ const void *str = 0;
+ sqlite3_value *value = tovalue(env, f, arg);
+ if (!value) return NULL;
+
+ length = sqlite3_value_bytes16(value) / 2; // in jchars
+ str = sqlite3_value_text16(value);
+ return str ? (*env)->NewString(env, str, length) : NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_sqlite_NativeDB_value_1blob(
+ JNIEnv *env, jobject this, jobject f, jint arg)
+{
+ jsize length;
+ jbyteArray jBlob;
+ jbyte *a;
+ const void *blob;
+ sqlite3_value *value = tovalue(env, f, arg);
+ if (!value) return NULL;
+
+ blob = sqlite3_value_blob(value);
+ if (!blob) return NULL;
+
+ length = sqlite3_value_bytes(value);
+ jBlob = (*env)->NewByteArray(env, length);
+ assert(jBlob); // out-of-memory
+
+ a = (*env)->GetPrimitiveArrayCritical(env, jBlob, 0);
+ memcpy(a, blob, length);
+ (*env)->ReleasePrimitiveArrayCritical(env, jBlob, a, 0);
+
+ return jBlob;
+}
+
+JNIEXPORT jdouble JNICALL Java_org_sqlite_NativeDB_value_1double(
+ JNIEnv *env, jobject this, jobject f, jint arg)
+{
+ sqlite3_value *value = tovalue(env, f, arg);
+ return value ? sqlite3_value_double(value) : 0;
+}
+
+JNIEXPORT jlong JNICALL Java_org_sqlite_NativeDB_value_1long(
+ JNIEnv *env, jobject this, jobject f, jint arg)
+{
+ sqlite3_value *value = tovalue(env, f, arg);
+ return value ? sqlite3_value_int64(value) : 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_value_1int(
+ JNIEnv *env, jobject this, jobject f, jint arg)
+{
+ sqlite3_value *value = tovalue(env, f, arg);
+ return value ? sqlite3_value_int(value) : 0;
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_value_1type(
+ JNIEnv *env, jobject this, jobject func, jint arg)
+{
+ return sqlite3_value_type(tovalue(env, func, arg));
+}
+
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_create_1function(
+ JNIEnv *env, jobject this, jstring name, jobject func)
+{
+ jint ret = 0;
+ const char *strname = 0;
+ int isAgg = 0;
+
+ static jfieldID udfdatalist = 0;
+ struct UDFData *udf = malloc(sizeof(struct UDFData));
+
+ assert(udf); // out-of-memory
+
+ if (!udfdatalist)
+ udfdatalist = (*env)->GetFieldID(env, dbclass, "udfdatalist", "J");
+
+ isAgg = (*env)->IsInstanceOf(env, func, aclass);
+ udf->func = (*env)->NewGlobalRef(env, func);
+ (*env)->GetJavaVM(env, &udf->vm);
+
+ // add new function def to linked list
+ udf->next = toref((*env)->GetLongField(env, this, udfdatalist));
+ (*env)->SetLongField(env, this, udfdatalist, fromref(udf));
+
+ strname = (*env)->GetStringUTFChars(env, name, 0);
+ assert(strname); // out-of-memory
+
+ ret = sqlite3_create_function(
+ gethandle(env, this),
+ strname, // function name
+ -1, // number of args
+ SQLITE_UTF16, // preferred chars
+ udf,
+ isAgg ? 0 :&xFunc,
+ isAgg ? &xStep : 0,
+ isAgg ? &xFinal : 0
+ );
+
+ (*env)->ReleaseStringUTFChars(env, name, strname);
+
+ return ret;
+}
+
+JNIEXPORT jint JNICALL Java_org_sqlite_NativeDB_destroy_1function(
+ JNIEnv *env, jobject this, jstring name)
+{
+ const char* strname = (*env)->GetStringUTFChars(env, name, 0);
+ sqlite3_create_function(
+ gethandle(env, this), strname, -1, SQLITE_UTF16, 0, 0, 0, 0
+ );
+ (*env)->ReleaseStringUTFChars(env, name, strname);
+}
+
+JNIEXPORT void JNICALL Java_org_sqlite_NativeDB_free_1functions(
+ JNIEnv *env, jobject this)
+{
+ // clean up all the malloc()ed UDFData instances using the
+ // linked list stored in DB.udfdatalist
+ jfieldID udfdatalist;
+ struct UDFData *udf, *udfpass;
+
+ udfdatalist = (*env)->GetFieldID(env, dbclass, "udfdatalist", "J");
+ udf = toref((*env)->GetLongField(env, this, udfdatalist));
+ (*env)->SetLongField(env, this, udfdatalist, 0);
+
+ while (udf) {
+ udfpass = udf->next;
+ (*env)->DeleteGlobalRef(env, udf->func);
+ free(udf);
+ udf = udfpass;
+ }
+}
+
+
+// COMPOUND FUNCTIONS ///////////////////////////////////////////////
+
+JNIEXPORT jobjectArray JNICALL Java_org_sqlite_NativeDB_column_1metadata(
+ JNIEnv *env, jobject this, jlong stmt)
+{
+ const char *zTableName, *zColumnName;
+ int pNotNull, pPrimaryKey, pAutoinc, i, colCount;
+ jobjectArray array;
+ jbooleanArray colData;
+ jboolean* colDataRaw;
+ sqlite3 *db;
+ sqlite3_stmt *dbstmt;
+
+ db = gethandle(env, this);
+ dbstmt = toref(stmt);
+
+ colCount = sqlite3_column_count(dbstmt);
+ array = (*env)->NewObjectArray(
+ env, colCount, (*env)->FindClass(env, "[Z"), NULL) ;
+ assert(array); // out-of-memory
+
+ colDataRaw = (jboolean*)malloc(3 * sizeof(jboolean));
+ assert(colDataRaw); // out-of-memory
+
+ for (i = 0; i < colCount; i++) {
+ // load passed column name and table name
+ zColumnName = sqlite3_column_name(dbstmt, i);
+ zTableName = sqlite3_column_table_name(dbstmt, i);
+
+ pNotNull = 0;
+ pPrimaryKey = 0;
+ pAutoinc = 0;
+
+ // request metadata for column and load into output variables
+ if (zTableName && zColumnName) {
+ sqlite3_table_column_metadata(
+ db, 0, zTableName, zColumnName,
+ 0, 0, &pNotNull, &pPrimaryKey, &pAutoinc
+ );
+ }
+
+ // load relevant metadata into 2nd dimension of return results
+ colDataRaw[0] = pNotNull;
+ colDataRaw[1] = pPrimaryKey;
+ colDataRaw[2] = pAutoinc;
+
+ colData = (*env)->NewBooleanArray(env, 3);
+ assert(colData); // out-of-memory
+
+ (*env)->SetBooleanArrayRegion(env, colData, 0, 3, colDataRaw);
+ (*env)->SetObjectArrayElement(env, array, i, colData);
+ }
+
+ free(colDataRaw);
+
+ return array;
+}
+
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.io.File;
+import java.sql.SQLException;
+
+import org.xerial.db.sql.sqlite.SQLiteJDBCLoader;
+
+/** This class provides a thin JNI layer over the SQLite3 C API. */
+final class NativeDB extends DB
+{
+ private static Boolean loaded = null;
+
+ static boolean load()
+ {
+ if (loaded != null)
+ return loaded == Boolean.TRUE;
+
+ SQLiteJDBCLoader.initialize(true);
+
+ String libpath = System.getProperty("org.sqlite.lib.path");
+ String libname = System.getProperty("org.sqlite.lib.name");
+ if (libname == null)
+ libname = System.mapLibraryName("sqlitejdbc");
+
+ try
+ {
+ if (libpath == null)
+ System.loadLibrary("sqlitejdbc");
+ else
+ System.load(new File(libpath, libname).getAbsolutePath());
+ }
+ catch (UnsatisfiedLinkError e)
+ {
+ loaded = Boolean.FALSE;
+ return false;
+ }
+
+ loaded = Boolean.TRUE;
+ return true;
+ }
+
+ /** linked list of all instanced UDFDatas */
+ private long udfdatalist = 0;
+
+ // WRAPPER FUNCTIONS ////////////////////////////////////////////
+
+ native synchronized void open(String filename) throws SQLException;
+
+ protected native synchronized void _close() throws SQLException;
+
+ native synchronized void interrupt();
+
+ native synchronized void busy_timeout(int ms);
+
+ // native synchronized void exec(String sql) throws SQLException;
+ protected native synchronized long prepare(String sql) throws SQLException;
+
+ native synchronized String errmsg();
+
+ native synchronized String libversion();
+
+ native synchronized int changes();
+
+ protected native synchronized int finalize(long stmt);
+
+ protected native synchronized int step(long stmt);
+
+ protected native synchronized int reset(long stmt);
+
+ native synchronized int clear_bindings(long stmt);
+
+ native synchronized int bind_parameter_count(long stmt);
+
+ native synchronized int column_count(long stmt);
+
+ native synchronized int column_type(long stmt, int col);
+
+ native synchronized String column_decltype(long stmt, int col);
+
+ native synchronized String column_table_name(long stmt, int col);
+
+ native synchronized String column_name(long stmt, int col);
+
+ native synchronized String column_text(long stmt, int col);
+
+ native synchronized byte[] column_blob(long stmt, int col);
+
+ native synchronized double column_double(long stmt, int col);
+
+ native synchronized long column_long(long stmt, int col);
+
+ native synchronized int column_int(long stmt, int col);
+
+ native synchronized int bind_null(long stmt, int pos);
+
+ native synchronized int bind_int(long stmt, int pos, int v);
+
+ native synchronized int bind_long(long stmt, int pos, long v);
+
+ native synchronized int bind_double(long stmt, int pos, double v);
+
+ native synchronized int bind_text(long stmt, int pos, String v);
+
+ native synchronized int bind_blob(long stmt, int pos, byte[] v);
+
+ native synchronized void result_null(long context);
+
+ native synchronized void result_text(long context, String val);
+
+ native synchronized void result_blob(long context, byte[] val);
+
+ native synchronized void result_double(long context, double val);
+
+ native synchronized void result_long(long context, long val);
+
+ native synchronized void result_int(long context, int val);
+
+ native synchronized void result_error(long context, String err);
+
+ native synchronized int value_bytes(Function f, int arg);
+
+ native synchronized String value_text(Function f, int arg);
+
+ native synchronized byte[] value_blob(Function f, int arg);
+
+ native synchronized double value_double(Function f, int arg);
+
+ native synchronized long value_long(Function f, int arg);
+
+ native synchronized int value_int(Function f, int arg);
+
+ native synchronized int value_type(Function f, int arg);
+
+ native synchronized int create_function(String name, Function func);
+
+ native synchronized int destroy_function(String name);
+
+ native synchronized void free_functions();
+
+ // COMPOUND FUNCTIONS (for optimisation) /////////////////////////
+
+ /**
+ * Provides metadata for the columns of a statement. Returns: res[col][0] =
+ * true if column constrained NOT NULL res[col][1] = true if column is part
+ * of the primary key res[col][2] = true if column is auto-increment
+ */
+ native synchronized boolean[][] column_metadata(long stmt);
+
+ static void throwex(String msg) throws SQLException
+ {
+ throw new SQLException(msg);
+ }
+}
--- /dev/null
+#include <stdlib.h>
+#include "sqlite3.h"
+
+/* Provides access to metadata across NestedVM 7-argument limit on functions.*/
+struct metadata {
+ int pNotNull;
+ int pPrimaryKey;
+ int pAutoinc;
+};
+
+int column_metadata_helper(
+ sqlite3 *db,
+ sqlite3_stmt *stmt,
+ int col,
+ struct metadata *p
+){
+ const char *zTableName, *zColumnName;
+ int rc = 0;
+
+ p->pNotNull = 0;
+ p->pPrimaryKey = 0;
+ p->pAutoinc = 0;
+
+ zTableName = sqlite3_column_table_name(stmt, col);
+ zColumnName = sqlite3_column_name(stmt, col);
+
+ if (zTableName && zColumnName) {
+ rc = sqlite3_table_column_metadata(
+ db, 0, zTableName, zColumnName, 0, 0,
+ &p->pNotNull, &p->pPrimaryKey, &p->pAutoinc
+ );
+ }
+
+ return rc;
+}
+
+
+extern int _call_java(int xType, int context, int args, int value);
+
+void xFunc_helper(sqlite3_context *context, int args, sqlite3_value** value)
+{
+ _call_java(1, (int)context, args, (int)value);
+}
+
+void xStep_helper(sqlite3_context *context, int args, sqlite3_value** value)
+{
+ _call_java(2, (int)context, args, (int)value);
+}
+
+void xFinal_helper(sqlite3_context *context)
+{
+ _call_java(3, (int)context, 0, 0);
+}
+
+/* create function if pos is non-negative, aggregate if agg is true */
+int create_function_helper(sqlite3 *db, const char *name, int pos, int agg)
+{
+ return sqlite3_create_function(db, name, -1, SQLITE_ANY, (void*)pos,
+ pos>=0 && !agg ? &xFunc_helper : 0,
+ pos>=0 && agg ? &xStep_helper : 0,
+ pos>=0 && agg ? &xFinal_helper : 0);
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+
+/** See comment in RS.java to explain the strange inheritance hierarchy. */
+final class PrepStmt extends RS implements PreparedStatement, ParameterMetaData, Codes
+{
+ private int columnCount;
+ private int paramCount;
+ private int batchPos;
+ private Object[] batch;
+
+ PrepStmt(Conn conn, String sql) throws SQLException
+ {
+ super(conn);
+
+ this.sql = sql;
+ db.prepare(this);
+ colsMeta = db.column_names(pointer);
+ columnCount = db.column_count(pointer);
+ paramCount = db.bind_parameter_count(pointer);
+ batch = new Object[paramCount];
+ batchPos = 0;
+ }
+
+ /** Weaker close to support object overriding (see docs in RS.java). */
+ public void close() throws SQLException
+ {
+ batch = null;
+ if (pointer == 0 || db == null)
+ clearRS();
+ else
+ clearParameters();
+ }
+
+ public void clearParameters() throws SQLException
+ {
+ checkOpen();
+ clearRS();
+ db.reset(pointer);
+ batchPos = 0;
+ if (batch != null)
+ for (int i = 0; i < batch.length; i++)
+ batch[i] = null;
+ }
+
+ protected void finalize() throws SQLException
+ {
+ db.finalize(this);
+ // TODO
+ }
+
+ public boolean execute() throws SQLException
+ {
+ checkExec();
+ clearRS();
+ db.reset(pointer); // TODO: needed?
+ resultsWaiting = db.execute(this, batch);
+ return columnCount != 0;
+ }
+
+ public ResultSet executeQuery() throws SQLException
+ {
+ checkExec();
+ if (columnCount == 0)
+ throw new SQLException("query does not return results");
+ clearRS();
+ db.reset(pointer); // TODO: needed?
+ resultsWaiting = db.execute(this, batch);
+ return getResultSet();
+ }
+
+ public int executeUpdate() throws SQLException
+ {
+ checkExec();
+ if (columnCount != 0)
+ throw new SQLException("query returns results");
+ clearRS();
+ db.reset(pointer);
+ return db.executeUpdate(this, batch);
+ }
+
+ public int[] executeBatch() throws SQLException
+ {
+ return db.executeBatch(pointer, batchPos / paramCount, batch);
+ }
+
+ public int getUpdateCount() throws SQLException
+ {
+ checkOpen();
+ if (pointer == 0 || resultsWaiting)
+ return -1;
+ return db.changes();
+ }
+
+ public void addBatch() throws SQLException
+ {
+ checkExec();
+ batchPos += paramCount;
+ if (batchPos + paramCount > batch.length)
+ {
+ Object[] nb = new Object[batch.length * 2];
+ System.arraycopy(batch, 0, nb, 0, batch.length);
+ batch = nb;
+ }
+ }
+
+ public void clearBatch() throws SQLException
+ {
+ clearParameters();
+ }
+
+ // ParameterMetaData FUNCTIONS //////////////////////////////////
+
+ public ParameterMetaData getParameterMetaData()
+ {
+ return this;
+ }
+
+ public int getParameterCount() throws SQLException
+ {
+ checkExec();
+ return paramCount;
+ }
+
+ public String getParameterClassName(int param) throws SQLException
+ {
+ checkExec();
+ return "java.lang.String";
+ }
+
+ public String getParameterTypeName(int pos)
+ {
+ return "VARCHAR";
+ }
+
+ public int getParameterType(int pos)
+ {
+ return Types.VARCHAR;
+ }
+
+ public int getParameterMode(int pos)
+ {
+ return parameterModeIn;
+ }
+
+ public int getPrecision(int pos)
+ {
+ return 0;
+ }
+
+ public int getScale(int pos)
+ {
+ return 0;
+ }
+
+ public int isNullable(int pos)
+ {
+ return parameterNullable;
+ }
+
+ public boolean isSigned(int pos)
+ {
+ return true;
+ }
+
+ public Statement getStatement()
+ {
+ return this;
+ }
+
+ // PARAMETER FUNCTIONS //////////////////////////////////////////
+
+ private void batch(int pos, Object value) throws SQLException
+ {
+ checkExec();
+ if (batch == null)
+ batch = new Object[paramCount];
+ batch[batchPos + pos - 1] = value;
+ }
+
+ public void setBoolean(int pos, boolean value) throws SQLException
+ {
+ setInt(pos, value ? 1 : 0);
+ }
+
+ public void setByte(int pos, byte value) throws SQLException
+ {
+ setInt(pos, (int) value);
+ }
+
+ public void setBytes(int pos, byte[] value) throws SQLException
+ {
+ batch(pos, value);
+ }
+
+ public void setDouble(int pos, double value) throws SQLException
+ {
+ batch(pos, new Double(value));
+ }
+
+ public void setFloat(int pos, float value) throws SQLException
+ {
+ setDouble(pos, value);
+ }
+
+ public void setInt(int pos, int value) throws SQLException
+ {
+ batch(pos, new Integer(value));
+ }
+
+ public void setLong(int pos, long value) throws SQLException
+ {
+ batch(pos, new Long(value));
+ }
+
+ public void setNull(int pos, int u1) throws SQLException
+ {
+ setNull(pos, u1, null);
+ }
+
+ public void setNull(int pos, int u1, String u2) throws SQLException
+ {
+ batch(pos, null);
+ }
+
+ public void setObject(int pos, Object value) throws SQLException
+ {
+ // TODO: catch wrapped primitives
+ batch(pos, value == null ? null : value.toString());
+ }
+
+ public void setObject(int p, Object v, int t) throws SQLException
+ {
+ setObject(p, v);
+ }
+
+ public void setObject(int p, Object v, int t, int s) throws SQLException
+ {
+ setObject(p, v);
+ }
+
+ public void setShort(int pos, short value) throws SQLException
+ {
+ setInt(pos, (int) value);
+ }
+
+ public void setString(int pos, String value) throws SQLException
+ {
+ batch(pos, value);
+ }
+
+ public void setDate(int pos, Date x) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ public void setDate(int pos, Date x, Calendar cal) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ public void setTime(int pos, Time x) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ public void setTime(int pos, Time x, Calendar cal) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ public void setTimestamp(int pos, Timestamp x) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ public void setTimestamp(int pos, Timestamp x, Calendar cal) throws SQLException
+ {
+ setLong(pos, x.getTime());
+ }
+
+ // UNUSED ///////////////////////////////////////////////////////
+
+ public boolean execute(String sql) throws SQLException
+ {
+ throw unused();
+ }
+
+ public int executeUpdate(String sql) throws SQLException
+ {
+ throw unused();
+ }
+
+ public ResultSet executeQuery(String sql) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void addBatch(String sql) throws SQLException
+ {
+ throw unused();
+ }
+
+ private SQLException unused()
+ {
+ return new SQLException("not supported by PreparedStatment");
+ }
+
+ @Override
+ public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setClob(int parameterIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setClob(int parameterIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, NClob value) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setNString(int parameterIndex, String value) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setRowId(int parameterIndex, RowId x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public boolean isPoolable() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public void setPoolable(boolean poolable) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean isWrapperFor(Class< ? > iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public int getHoldability() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public Reader getNCharacterStream(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public Reader getNCharacterStream(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public NClob getNClob(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public NClob getNClob(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public String getNString(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public String getNString(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public RowId getRowId(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public RowId getRowId(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public SQLXML getSQLXML(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public SQLXML getSQLXML(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, NClob clob) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, NClob clob) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNString(int columnIndex, String string) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNString(String columnLabel, String string) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateRowId(int columnIndex, RowId x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateRowId(String columnLabel, RowId x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.sql.*;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.util.Calendar;
+import java.util.Map;
+
+/** Implements a JDBC ResultSet.
+ *
+ * As only one ResultSet can exist per statement, this implementation
+ * takes the odd step of making the ResultSet and Statement the same
+ * object. This means:
+ * ResultSet rs = statement.executeQuery("SELECT ...");
+ *
+ * Generates no temporary ResultSet object, it just returns itself.
+ * When a great many ResultSets are used (e.g. in a loop), this can
+ * help reduce the load on the Garbage collector.
+ *
+ * As a result of this odd arrangement, Stmt and PrepStmt must
+ * extend RS:
+ * Object -- Unused -- RS -- Stmt
+ * | -- PrepStmt
+ *
+ * Such inheritance requires careful checking of the object state,
+ * for which the check...() functions and isRS() function handle.
+ */
+abstract class RS extends Unused implements ResultSet, ResultSetMetaData, Codes
+{
+ Conn conn;
+ DB db;
+
+ String sql = null;
+ long pointer = 0;
+ boolean isAfterLast = false;
+ boolean resultsWaiting = false;
+
+ int maxRows; // max. number of rows as set by a Statement
+ String[] cols = null; // if null, the RS is closed()
+ String[] colsMeta = null; // same as cols, but used by Meta interface
+ boolean[][] meta = null;
+
+ private int limitRows; // 0 means no limit, must check against maxRows
+ private int row = 1; // number of current row, starts at 1
+ private int lastCol; // last column accessed, for wasNull(). -1 if none
+
+ RS(Conn conn) {
+ this.conn = conn;
+ this.db = conn.db();
+ }
+
+
+ // INTERNAL FUNCTIONS ///////////////////////////////////////////
+
+ protected final void checkOpen() throws SQLException {
+ if (db == null) throw new SQLException("statement is closed");
+ }
+ protected final void checkExec() throws SQLException {
+ if (pointer == 0) throw new SQLException("statement is not executing");
+ }
+ protected final void checkRS() throws SQLException {
+ if (db == null || !isRS()) throw new SQLException("ResultSet closed");
+ }
+ /** Returns true if this Statement is an currently an active ResultSet. */
+ protected final boolean isRS() { return cols != null; }
+
+ // takes col in [1,x] form, returns in [0,x-1] form
+ private int checkCol(int col) throws SQLException {
+ checkOpen();
+ if (colsMeta == null) throw new IllegalStateException(
+ "SQLite JDBC: inconsistent internal state");
+ if (col < 1 || col > colsMeta.length) throw new SQLException(
+ "column " + col + " out of bounds [1," + colsMeta.length + "]");
+ return --col;
+ }
+
+ // takes col in [1,x] form, marks it as last accessed and returns [0,x-1]
+ private int markCol(int col) throws SQLException {
+ checkRS(); checkCol(col); lastCol = col; return --col;
+ }
+
+ private void checkMeta() throws SQLException {
+ checkCol(1);
+ if (meta == null) meta = db.column_metadata(pointer);
+ }
+
+
+ // ResultSet Functions //////////////////////////////////////////
+
+ // returns col in [1,x] form
+ public int findColumn(String col) throws SQLException {
+ checkRS();
+ for (int i=0; i < cols.length; i++)
+ if (col.equalsIgnoreCase(cols[i])) return i+1;
+ throw new SQLException("no such column: '"+col+"'");
+ }
+
+ public boolean next() throws SQLException {
+ if (isAfterLast) return false; // finished ResultSet
+ lastCol = -1;
+
+ // first row is loaded by execute(), so do not step() again
+ if (row == 1) { row++; return true; }
+
+ // check if we are row limited by the statement or the ResultSet
+ if (maxRows != 0 && row > maxRows) return false;
+ if (limitRows != 0 && row >= limitRows) return false;
+
+ // do the real work
+ int rc = db.step(pointer);
+ if (rc == SQLITE_ERROR)
+ db.reset(pointer);
+
+ switch (rc) {
+ case SQLITE_BUSY:
+ throw new SQLException("database locked");
+ case SQLITE_DONE:
+ isAfterLast = true;
+ close(); // agressive closing to avoid writer starvation
+ return false;
+ case SQLITE_ROW: row++; return true;
+ case SQLITE_MISUSE:
+ throw new SQLException("JDBC internal consistency error");
+ case SQLITE_ERROR:
+ default:
+ db.throwex(); return false;
+ }
+ }
+
+ public int getType() throws SQLException { return TYPE_FORWARD_ONLY; }
+
+ public int getFetchSize() throws SQLException { return limitRows; }
+ public void setFetchSize(int rows) throws SQLException {
+ if (0 > rows || (maxRows != 0 && rows > maxRows))
+ throw new SQLException("fetch size " + rows
+ + " out of bounds " + maxRows);
+ limitRows = rows;
+ }
+
+ public int getFetchDirection() throws SQLException {
+ checkOpen(); return ResultSet.FETCH_FORWARD; }
+ public void setFetchDirection(int d) throws SQLException {
+ checkOpen();
+ if (d != ResultSet.FETCH_FORWARD)
+ throw new SQLException("only FETCH_FORWARD direction supported");
+ }
+
+ public boolean isAfterLast() throws SQLException { return isAfterLast; }
+ public boolean isBeforeFirst() throws SQLException {
+ return !isAfterLast && row == 1; }
+ public boolean isFirst() throws SQLException { return row == 2; }
+ public boolean isLast() throws SQLException { // FIXME
+ throw new SQLException("function not yet implemented for SQLite"); }
+
+ /** Resets the RS in a way safe for both Stmt and PrepStmt.
+ * Full reset happens in Stmt.close(). */
+ void clearRS() throws SQLException {
+ cols = null;
+ isAfterLast = true;
+ limitRows = 0;
+ row = 1;
+ lastCol = -1;
+ }
+ protected void finalize() throws SQLException { clearRS(); }
+
+ public int getRow() throws SQLException { return row; }
+
+ public boolean wasNull() throws SQLException {
+ return db.column_type(pointer, markCol(lastCol)) == SQLITE_NULL;
+ }
+
+
+ // DATA ACCESS FUNCTIONS ////////////////////////////////////////
+
+ public boolean getBoolean(int col) throws SQLException {
+ return getInt(col) == 0 ? false : true; }
+ public boolean getBoolean(String col) throws SQLException {
+ return getBoolean(findColumn(col)); }
+
+ public byte getByte(int col) throws SQLException {
+ return (byte)getInt(col); }
+ public byte getByte(String col) throws SQLException {
+ return getByte(findColumn(col)); }
+
+ public byte[] getBytes(int col) throws SQLException {
+ return db.column_blob(pointer, markCol(col)); }
+ public byte[] getBytes(String col) throws SQLException {
+ return getBytes(findColumn(col)); }
+
+ public Date getDate(int col) throws SQLException {
+ return new Date(db.column_long(pointer, markCol(col))); }
+ public Date getDate(int col, Calendar cal) throws SQLException {
+ if (cal == null) return getDate(col);
+ cal.setTimeInMillis(db.column_long(pointer, markCol(col)));
+ return new Date(cal.getTime().getTime());
+ }
+ public Date getDate(String col) throws SQLException {
+ return getDate(findColumn(col), Calendar.getInstance()); }
+ public Date getDate(String col, Calendar cal) throws SQLException {
+ return getDate(findColumn(col), cal); }
+
+ public double getDouble(int col) throws SQLException {
+ return db.column_double(pointer, markCol(col)); }
+ public double getDouble(String col) throws SQLException {
+ return getDouble(findColumn(col)); }
+
+ public float getFloat(int col) throws SQLException {
+ return (float)db.column_double(pointer, markCol(col)); }
+ public float getFloat(String col) throws SQLException {
+ return getFloat(findColumn(col)); }
+
+ public int getInt(int col) throws SQLException {
+ return db.column_int(pointer, markCol(col)); }
+ public int getInt(String col) throws SQLException {
+ return getInt(findColumn(col)); }
+
+ public long getLong(int col) throws SQLException {
+ return db.column_long(pointer, markCol(col)); }
+ public long getLong(String col) throws SQLException {
+ return getLong(findColumn(col)); }
+
+ public short getShort(int col) throws SQLException {
+ return (short)getInt(col); }
+ public short getShort(String col) throws SQLException {
+ return getShort(findColumn(col)); }
+
+ public String getString(int col) throws SQLException {
+ return db.column_text(pointer, markCol(col)); }
+ public String getString(String col) throws SQLException {
+ return getString(findColumn(col)); }
+
+ public Time getTime(int col) throws SQLException {
+ return new Time(db.column_long(pointer, markCol(col))); }
+ public Time getTime(int col, Calendar cal) throws SQLException {
+ if (cal == null) return getTime(col);
+ cal.setTimeInMillis(db.column_long(pointer, markCol(col)));
+ return new Time(cal.getTime().getTime());
+ }
+ public Time getTime(String col) throws SQLException {
+ return getTime(findColumn(col)); }
+ public Time getTime(String col, Calendar cal) throws SQLException {
+ return getTime(findColumn(col), cal); }
+
+ public Timestamp getTimestamp(int col) throws SQLException {
+ return new Timestamp(db.column_long(pointer, markCol(col))); }
+ public Timestamp getTimestamp(int col, Calendar cal) throws SQLException {
+ if (cal == null) return getTimestamp(col);
+ cal.setTimeInMillis(db.column_long(pointer, markCol(col)));
+ return new Timestamp(cal.getTime().getTime());
+ }
+ public Timestamp getTimestamp(String col) throws SQLException {
+ return getTimestamp(findColumn(col)); }
+ public Timestamp getTimestamp(String c, Calendar ca) throws SQLException {
+ return getTimestamp(findColumn(c), ca); }
+
+ public Object getObject(int col) throws SQLException {
+ switch (db.column_type(pointer, checkCol(col))) {
+ case SQLITE_INTEGER: return new Integer(getInt(col));
+ case SQLITE_FLOAT: return new Double(getDouble(col));
+ case SQLITE_BLOB: return getBytes(col);
+ case SQLITE_NULL: return null;
+ case SQLITE_TEXT:
+ default:
+ return getString(col);
+ }
+ }
+ public Object getObject(String col) throws SQLException {
+ return getObject(findColumn(col)); }
+
+
+ // ResultSetMetaData Functions //////////////////////////////////
+
+ // we do not need to check the RS is open, only that colsMeta
+ // is not null, done with checkCol(int).
+
+ public String getCatalogName(int col) throws SQLException {
+ return db.column_table_name(pointer, checkCol(col)); }
+ public String getColumnClassName(int col) throws SQLException {
+ checkCol(col); return "java.lang.Object"; }
+ public int getColumnCount() throws SQLException {
+ checkCol(1); return colsMeta.length;
+ }
+ public int getColumnDisplaySize(int col) throws SQLException {
+ return Integer.MAX_VALUE; }
+ public String getColumnLabel(int col) throws SQLException {
+ return getColumnName(col); }
+ public String getColumnName(int col) throws SQLException {
+ return db.column_name(pointer, checkCol(col)); }
+ public int getColumnType(int col) throws SQLException {
+ switch (db.column_type(pointer, checkCol(col))) {
+ case SQLITE_INTEGER: return Types.INTEGER;
+ case SQLITE_FLOAT: return Types.FLOAT;
+ case SQLITE_BLOB: return Types.BLOB;
+ case SQLITE_NULL: return Types.NULL;
+ case SQLITE_TEXT:
+ default:
+ return Types.VARCHAR;
+ }
+ }
+ public String getColumnTypeName(int col) throws SQLException {
+ return db.column_decltype(pointer, checkCol(col));
+ }
+ public int getPrecision(int col) throws SQLException { return 0; } // FIXME
+ public int getScale(int col) throws SQLException { return 0; }
+ public String getSchemaName(int col) throws SQLException { return ""; }
+ public String getTableName(int col) throws SQLException {
+ return db.column_table_name(pointer, checkCol(col)); }
+ public int isNullable(int col) throws SQLException {
+ checkMeta();
+ return meta[checkCol(col)][1] ? columnNoNulls: columnNullable;
+ }
+ public boolean isAutoIncrement(int col) throws SQLException {
+ checkMeta(); return meta[checkCol(col)][2]; }
+ public boolean isCaseSensitive(int col) throws SQLException { return true; }
+ public boolean isCurrency(int col) throws SQLException { return false; }
+ public boolean isDefinitelyWritable(int col) throws SQLException {
+ return true; } // FIXME: check db file constraints?
+ public boolean isReadOnly(int col) throws SQLException { return false; }
+ public boolean isSearchable(int col) throws SQLException { return true; }
+ public boolean isSigned(int col) throws SQLException { return false; }
+ public boolean isWritable(int col) throws SQLException { return true; }
+
+ public int getConcurrency() throws SQLException { return CONCUR_READ_ONLY; }
+
+ public boolean rowDeleted() throws SQLException { return false; }
+ public boolean rowInserted() throws SQLException { return false; }
+ public boolean rowUpdated() throws SQLException { return false; }
+
+ public int getResultSetConcurrency() throws SQLException {
+ checkOpen(); return ResultSet.CONCUR_READ_ONLY; }
+ public int getResultSetHoldability() throws SQLException {
+ checkOpen(); return ResultSet.CLOSE_CURSORS_AT_COMMIT; }
+ public int getResultSetType() throws SQLException {
+ checkOpen(); return ResultSet.TYPE_FORWARD_ONLY; }
+
+
+ // SHARED BY Stmt, PrepStmt /////////////////////////////////////
+
+ public String getCursorName() throws SQLException { return null; }
+ public void setCursorName(String name) {}
+
+ public SQLWarning getWarnings() throws SQLException { return null; }
+ public void clearWarnings() throws SQLException {}
+
+ public Connection getConnection() throws SQLException {
+ checkOpen(); return conn; }
+ public ResultSetMetaData getMetaData() throws SQLException {
+ checkOpen(); return this; }
+
+ public void cancel() throws SQLException { checkExec(); db.interrupt(); }
+ public int getQueryTimeout() throws SQLException {
+ checkOpen(); return conn.getTimeout(); }
+ public void setQueryTimeout(int seconds) throws SQLException {
+ checkOpen();
+ if (seconds < 0) throw new SQLException("query timeout must be >= 0");
+ conn.setTimeout(1000 * seconds);
+ }
+
+ // TODO: write test
+ public int getMaxRows() throws SQLException { checkOpen(); return maxRows; }
+ public void setMaxRows(int max) throws SQLException {
+ checkOpen();
+ if (max < 0) throw new SQLException("max row count must be >= 0");
+ maxRows = max;
+ }
+
+ public int getMaxFieldSize() throws SQLException { return 0; }
+ public void setMaxFieldSize(int max) throws SQLException {
+ if (max < 0) throw new SQLException(
+ "max field size "+max+" cannot be negative");
+ }
+
+ public ResultSet getResultSet() throws SQLException {
+ checkExec();
+ if (isRS()) throw new SQLException("ResultSet already requested");
+ if (db.column_count(pointer) == 0) throw new SQLException(
+ "no ResultSet available");
+ if (colsMeta == null) colsMeta = db.column_names(pointer);
+ cols = colsMeta;
+
+ isAfterLast = !resultsWaiting;
+ if (resultsWaiting) resultsWaiting = false;
+ return this;
+ }
+
+ /** As SQLite's last_insert_rowid() function is DB-specific not
+ * statement specific, this function introduces a race condition
+ * if the same connection is used by two threads and both insert. */
+ public ResultSet getGeneratedKeys() throws SQLException {
+ return ((MetaData)conn.getMetaData()).getGeneratedKeys();
+ }
+
+ /** SQLite does not support multiple results from execute(). */
+ public boolean getMoreResults() throws SQLException {
+ return getMoreResults(0);
+ }
+ public boolean getMoreResults(int c) throws SQLException {
+ checkOpen();
+ close(); // as we never have another result, clean up pointer
+ return false;
+ }
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.sql.BatchUpdateException;
+import java.sql.NClob;
+import java.sql.ResultSet;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.util.ArrayList;
+
+/** See comment in RS.java to explain the strange inheritance hierarchy. */
+class Stmt extends RS implements Statement, Codes
+{
+ private ArrayList batch = null;
+
+ Stmt(Conn conn)
+ {
+ super(conn);
+ }
+
+ /** Calls sqlite3_step() and sets up results. Expects a clean stmt. */
+ protected boolean exec() throws SQLException
+ {
+ if (pointer == 0)
+ throw new SQLException("SQLite JDBC internal error: pointer == 0 on exec.");
+ if (isRS())
+ throw new SQLException("SQLite JDBC internal error: isRS() on exec.");
+
+ boolean rc = false;
+ try
+ {
+ rc = db.execute(this, null);
+ }
+ finally
+ {
+ resultsWaiting = rc;
+ }
+
+ return db.column_count(pointer) != 0;
+ }
+
+ // PUBLIC INTERFACE /////////////////////////////////////////////
+
+ public Statement getStatement()
+ {
+ return this;
+ }
+
+ /**
+ * More lax than JDBC spec, a Statement can be reused after close(). This is
+ * to support Stmt and RS sharing a heap object.
+ */
+ public void close() throws SQLException
+ {
+ if (pointer == 0)
+ return;
+ clearRS();
+ colsMeta = null;
+ meta = null;
+ batch = null;
+ int resp = db.finalize(this);
+ if (resp != SQLITE_OK && resp != SQLITE_MISUSE)
+ db.throwex();
+ }
+
+ /**
+ * The JVM does not ensure finalize() is called, so a Map in the DB class
+ * keeps track of statements for finalization.
+ */
+ protected void finalize() throws SQLException
+ {
+ close();
+ }
+
+ public int getUpdateCount() throws SQLException
+ {
+ checkOpen();
+ if (pointer == 0 || resultsWaiting)
+ return -1;
+ return db.changes();
+ }
+
+ public boolean execute(String sql) throws SQLException
+ {
+ checkOpen();
+ close();
+ this.sql = sql;
+ db.prepare(this);
+ return exec();
+ }
+
+ public ResultSet executeQuery(String sql) throws SQLException
+ {
+ checkOpen();
+ close();
+ this.sql = sql;
+ db.prepare(this);
+ if (!exec())
+ {
+ close();
+ throw new SQLException("query does not return ResultSet");
+ }
+ return getResultSet();
+ }
+
+ public int executeUpdate(String sql) throws SQLException
+ {
+ checkOpen();
+ close();
+ this.sql = sql;
+ int changes = 0;
+ try
+ {
+ db.prepare(this);
+ changes = db.executeUpdate(this, null);
+ }
+ finally
+ {
+ close();
+ }
+ return changes;
+ }
+
+ public void addBatch(String sql) throws SQLException
+ {
+ checkOpen();
+ if (batch == null)
+ batch = new ArrayList();
+ batch.add(sql);
+ }
+
+ public void clearBatch() throws SQLException
+ {
+ checkOpen();
+ if (batch != null)
+ batch.clear();
+ }
+
+ public int[] executeBatch() throws SQLException
+ {
+ // TODO: optimise
+ checkOpen();
+ close();
+ if (batch == null)
+ return new int[] {};
+
+ int[] changes = new int[batch.size()];
+
+ synchronized (db)
+ {
+ try
+ {
+ for (int i = 0; i < changes.length; i++)
+ {
+ try
+ {
+ sql = (String) batch.get(i);
+ db.prepare(this);
+ changes[i] = db.executeUpdate(this, null);
+ }
+ catch (SQLException e)
+ {
+ throw new BatchUpdateException("batch entry " + i + ": " + e.getMessage(), changes);
+ }
+ finally
+ {
+ db.finalize(this);
+ }
+ }
+ }
+ finally
+ {
+ batch.clear();
+ }
+ }
+
+ return changes;
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isPoolable() throws SQLException
+ {
+ return false;
+ }
+
+ @Override
+ public void setPoolable(boolean poolable) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public boolean isWrapperFor(Class< ? > iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public int getHoldability() throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public Reader getNCharacterStream(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public Reader getNCharacterStream(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public NClob getNClob(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public NClob getNClob(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public String getNString(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public String getNString(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public RowId getRowId(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public RowId getRowId(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public SQLXML getSQLXML(int columnIndex) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public SQLXML getSQLXML(String columnLabel) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(int columnIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateClob(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ throw new SQLException("not yet implemented");
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, NClob clob) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, NClob clob) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNString(int columnIndex, String string) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateNString(String columnLabel, String string) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateRowId(int columnIndex, RowId x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateRowId(String columnLabel, RowId x) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+
+ @Override
+ public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException
+ {
+ // TODO Auto-generated method stub
+ throw new SQLException("not yet implemented");
+
+ }
+}
--- /dev/null
+/* Copyright 2006 David Crawshaw, see LICENSE file for licensing [BSD]. */
+package org.sqlite;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.Ref;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Map;
+
+/** Unused JDBC functions from Statement, PreparedStatement and ResultSet. */
+abstract class Unused
+{
+ private SQLException unused()
+ {
+ return new SQLException("not implemented by SQLite JDBC driver");
+ }
+
+ // Statement ////////////////////////////////////////////////////
+
+ public void setEscapeProcessing(boolean enable) throws SQLException
+ {
+ throw unused();
+ }
+
+ public boolean execute(String sql, int[] colinds) throws SQLException
+ {
+ throw unused();
+ }
+
+ public boolean execute(String sql, String[] colnames) throws SQLException
+ {
+ throw unused();
+ }
+
+ public int executeUpdate(String sql, int autoKeys) throws SQLException
+ {
+ throw unused();
+ }
+
+ public int executeUpdate(String sql, int[] colinds) throws SQLException
+ {
+ throw unused();
+ }
+
+ public int executeUpdate(String sql, String[] cols) throws SQLException
+ {
+ throw unused();
+ }
+
+ public boolean execute(String sql, int autokeys) throws SQLException
+ {
+ throw unused();
+ }
+
+ // PreparedStatement ////////////////////////////////////////////
+
+ public void setArray(int i, Array x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setBlob(int i, Blob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setCharacterStream(int pos, Reader reader, int length) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setClob(int i, Clob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setRef(int i, Ref x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setUnicodeStream(int pos, InputStream x, int length) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void setURL(int pos, URL x) throws SQLException
+ {
+ throw unused();
+ }
+
+ // ResultSet ////////////////////////////////////////////////////
+
+ public Array getArray(int i) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Array getArray(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getAsciiStream(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getAsciiStream(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public BigDecimal getBigDecimal(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public BigDecimal getBigDecimal(int col, int s) throws SQLException
+ {
+ throw unused();
+ }
+
+ public BigDecimal getBigDecimal(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public BigDecimal getBigDecimal(String col, int s) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getBinaryStream(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getBinaryStream(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Blob getBlob(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Blob getBlob(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Reader getCharacterStream(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Reader getCharacterStream(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Clob getClob(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Clob getClob(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Object getObject(int col, Map<String, Class< ? >> map) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Object getObject(String col, Map<String, Class< ? >> map) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Ref getRef(int i) throws SQLException
+ {
+ throw unused();
+ }
+
+ public Ref getRef(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getUnicodeStream(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public InputStream getUnicodeStream(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public URL getURL(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public URL getURL(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void insertRow() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public void moveToCurrentRow() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public void moveToInsertRow() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public boolean last() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public boolean previous() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public boolean relative(int rows) throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public boolean absolute(int row) throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public void afterLast() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public void beforeFirst() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public boolean first() throws SQLException
+ {
+ throw new SQLException("ResultSet is TYPE_FORWARD_ONLY");
+ }
+
+ public void cancelRowUpdates() throws SQLException
+ {
+ throw unused();
+ }
+
+ public void deleteRow() throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateArray(int col, Array x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateArray(String col, Array x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateAsciiStream(int col, InputStream x, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateAsciiStream(String col, InputStream x, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBigDecimal(int col, BigDecimal x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBigDecimal(String col, BigDecimal x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBinaryStream(int c, InputStream x, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBinaryStream(String c, InputStream x, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBlob(int col, Blob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBlob(String col, Blob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBoolean(int col, boolean x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBoolean(String col, boolean x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateByte(int col, byte x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateByte(String col, byte x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBytes(int col, byte[] x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateBytes(String col, byte[] x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateCharacterStream(int c, Reader x, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateCharacterStream(String c, Reader r, int l) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateClob(int col, Clob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateClob(String col, Clob x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateDate(int col, Date x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateDate(String col, Date x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateDouble(int col, double x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateDouble(String col, double x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateFloat(int col, float x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateFloat(String col, float x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateInt(int col, int x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateInt(String col, int x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateLong(int col, long x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateLong(String col, long x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateNull(int col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateNull(String col) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateObject(int c, Object x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateObject(int c, Object x, int s) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateObject(String col, Object x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateObject(String c, Object x, int s) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateRef(int col, Ref x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateRef(String c, Ref x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateRow() throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateShort(int c, short x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateShort(String c, short x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateString(int c, String x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateString(String c, String x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateTime(int c, Time x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateTime(String c, Time x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateTimestamp(int c, Timestamp x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void updateTimestamp(String c, Timestamp x) throws SQLException
+ {
+ throw unused();
+ }
+
+ public void refreshRow() throws SQLException
+ {
+ throw unused();
+ }
+}
setSQLiteNativeLibraryPath();\r
}\r
\r
+ public static void initialize(boolean forceReload)\r
+ {\r
+ if (forceReload)\r
+ extracted = false;\r
+ setSQLiteNativeLibraryPath();\r
+ }\r
+\r
private static boolean extractLibraryFile(String libraryResourcePath, String libraryFolder, String libraryFileName)\r
{\r
File libFile = new File(libraryFolder, libraryFileName);\r
@Test
public void query() throws ClassNotFoundException
{
- SQLiteJDBCLoader.initialize();
+ // SQLiteJDBCLoader.initialize();
// load the sqlite-JDBC driver into the current class loader
Class.forName("org.sqlite.JDBC");