diff options
Diffstat (limited to 'sql')
136 files changed, 44856 insertions, 0 deletions
diff --git a/sql/MODULE_LICENSE_APACHE2 b/sql/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/sql/MODULE_LICENSE_APACHE2 diff --git a/sql/MODULE_LICENSE_BSD_LIKE b/sql/MODULE_LICENSE_BSD_LIKE new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/sql/MODULE_LICENSE_BSD_LIKE diff --git a/sql/src/main/java/SQLite/Authorizer.java b/sql/src/main/java/SQLite/Authorizer.java new file mode 100644 index 0000000..cdc321d --- /dev/null +++ b/sql/src/main/java/SQLite/Authorizer.java @@ -0,0 +1,25 @@ +package SQLite; + +/** + * Callback interface for SQLite's authorizer function. + */ + +public interface Authorizer { + + /** + * Callback to authorize access. + * + * @param what integer indicating type of access + * @param arg1 first argument (table, view, index, or trigger name) + * @param arg2 second argument (file, table, or column name) + * @param arg3 third argument (database name) + * @param arg4 third argument (trigger name) + * @return Constants.SQLITE_OK for success, Constants.SQLITE_IGNORE + * for don't allow access but don't raise an error, Constants.SQLITE_DENY + * for abort SQL statement with error. + */ + + public int authorize(int what, String arg1, String arg2, String arg3, + String arg4); +} + diff --git a/sql/src/main/java/SQLite/Blob.java b/sql/src/main/java/SQLite/Blob.java new file mode 100644 index 0000000..3de9f8a --- /dev/null +++ b/sql/src/main/java/SQLite/Blob.java @@ -0,0 +1,323 @@ +package SQLite; + +import java.io.*; + +/** + * Internal class implementing java.io.InputStream on + * SQLite 3.4.0 incremental blob I/O interface. + */ + +class BlobR extends InputStream { + + /** + * Blob instance + */ + + private Blob blob; + + /** + * Read position, file pointer. + */ + + private int pos; + + /** + * Contruct InputStream from blob instance. + */ + + BlobR(Blob blob) { + this.blob = blob; + this.pos = 0; + } + + /** + * Return number of available bytes for reading. + * @return available input bytes + */ + + public int available() throws IOException { + int ret = blob.size - pos; + return (ret < 0) ? 0 : ret; + } + + /** + * Mark method; dummy to satisfy InputStream class. + */ + + public void mark(int limit) { + } + + /** + * Reset method; dummy to satisfy InputStream class. + */ + + public void reset() throws IOException { + } + + /** + * Mark support; not for this class. + * @return always false + */ + + public boolean markSupported() { + return false; + } + + /** + * Close this blob InputStream. + */ + + public void close() throws IOException { + blob.close(); + blob = null; + pos = 0; + } + + /** + * Skip over blob data. + */ + + public long skip(long n) throws IOException { + long ret = pos + n; + if (ret < 0) { + ret = 0; + pos = 0; + } else if (ret > blob.size) { + ret = blob.size; + pos = blob.size; + } else { + pos = (int) ret; + } + return ret; + } + + /** + * Read single byte from blob. + * @return byte read + */ + + public int read() throws IOException { + byte b[] = new byte[1]; + int n = blob.read(b, 0, pos, b.length); + if (n > 0) { + pos += n; + return b[0]; + } + return -1; + } + + /** + * Read byte array from blob. + * @param b byte array to be filled + * @return number of bytes read + */ + + public int read(byte b[]) throws IOException { + int n = blob.read(b, 0, pos, b.length); + if (n > 0) { + pos += n; + return n; + } + return -1; + } + + /** + * Read slice of byte array from blob. + * @param b byte array to be filled + * @param off offset into byte array + * @param len length to be read + * @return number of bytes read + */ + + public int read(byte b[], int off, int len) throws IOException { + if (off + len > b.length) { + len = b.length - off; + } + if (len < 0) { + return -1; + } + if (len == 0) { + return 0; + } + int n = blob.read(b, off, pos, len); + if (n > 0) { + pos += n; + return n; + } + return -1; + } +} + +/** + * Internal class implementing java.io.OutputStream on + * SQLite 3.4.0 incremental blob I/O interface. + */ + +class BlobW extends OutputStream { + + /** + * Blob instance + */ + + private Blob blob; + + /** + * Read position, file pointer. + */ + + private int pos; + + /** + * Contruct OutputStream from blob instance. + */ + + BlobW(Blob blob) { + this.blob = blob; + this.pos = 0; + } + + /** + * Flush blob; dummy to satisfy OutputStream class. + */ + + public void flush() throws IOException { + } + + /** + * Close this blob OutputStream. + */ + + public void close() throws IOException { + blob.close(); + blob = null; + pos = 0; + } + + /** + * Write blob data. + * @param v byte to be written at current position. + */ + + public void write(int v) throws IOException { + byte b[] = new byte[1]; + b[0] = (byte) v; + pos += blob.write(b, 0, pos, 1); + } + + /** + * Write blob data. + * @param b byte array to be written at current position. + */ + + public void write(byte[] b) throws IOException { + if (b != null && b.length > 0) { + pos += blob.write(b, 0, pos, b.length); + } + } + + /** + * Write blob data. + * @param b byte array to be written. + * @param off offset within byte array + * @param len length of data to be written + */ + + public void write(byte[] b, int off, int len) throws IOException { + if (b != null) { + if (off + len > b.length) { + len = b.length - off; + } + if (len <= 0) { + return; + } + pos += blob.write(b, off, pos, len); + } + } +} + +/** + * Class to represent SQLite3 3.4.0 incremental blob I/O interface. + * + * Note, that all native methods of this class are + * not synchronized, i.e. it is up to the caller + * to ensure that only one thread is in these + * methods at any one time. + */ + +public class Blob { + + /** + * Internal handle for the SQLite3 blob. + */ + + private long handle = 0; + + /** + * Cached size of blob, setup right after blob + * has been opened. + */ + + protected int size = 0; + + /** + * Return InputStream for this blob + * @return InputStream + */ + + public InputStream getInputStream() { + return (InputStream) new BlobR(this); + } + + /** + * Return OutputStream for this blob + * @return OutputStream + */ + + public OutputStream getOutputStream() { + return (OutputStream) new BlobW(this); + } + + /** + * Close blob. + */ + + public native void close(); + + /** + * Internal blob write method. + * @param b byte array to be written + * @param off offset into byte array + * @param pos offset into blob + * @param len length to be written + * @return number of bytes written to blob + */ + + native int write(byte[] b, int off, int pos, int len) throws IOException; + + /** + * Internal blob read method. + * @param b byte array to be written + * @param off offset into byte array + * @param pos offset into blob + * @param len length to be written + * @return number of bytes written to blob + */ + + native int read(byte[] b, int off, int pos, int len) throws IOException; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sql/src/main/java/SQLite/BusyHandler.java b/sql/src/main/java/SQLite/BusyHandler.java new file mode 100644 index 0000000..c39b39d --- /dev/null +++ b/sql/src/main/java/SQLite/BusyHandler.java @@ -0,0 +1,20 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined busy handler. + */ + +public interface BusyHandler { + + /** + * Invoked when a table is locked by another process + * or thread. The method should return true for waiting + * until the table becomes unlocked, or false in order + * to abandon the action.<BR><BR> + * + * @param table the name of the locked table + * @param count number of times the table was locked + */ + + public boolean busy(String table, int count); +} diff --git a/sql/src/main/java/SQLite/Callback.java b/sql/src/main/java/SQLite/Callback.java new file mode 100644 index 0000000..3eeb605 --- /dev/null +++ b/sql/src/main/java/SQLite/Callback.java @@ -0,0 +1,68 @@ +package SQLite; + +/** + * Callback interface for SQLite's query results. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * class TableFmt implements SQLite.Callback { + * public void columns(String cols[]) { + * System.out.println("<TH><TR>"); + * for (int i = 0; i < cols.length; i++) { + * System.out.println("<TD>" + cols[i] + "</TD>"); + * } + * System.out.println("</TR></TH>"); + * } + * public boolean newrow(String cols[]) { + * System.out.println("<TR>"); + * for (int i = 0; i < cols.length; i++) { + * System.out.println("<TD>" + cols[i] + "</TD>"); + * } + * System.out.println("</TR>"); + * return false; + * } + * } + * ... + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * System.out.println("<TABLE>"); + * db.exec("select * from TEST", new TableFmt()); + * System.out.println("</TABLE>"); + * ... + * </PRE> + */ + +public interface Callback { + + /** + * Reports column names of the query result. + * This method is invoked first (and once) when + * the SQLite engine returns the result set.<BR><BR> + * + * @param coldata string array holding the column names + */ + + public void columns(String coldata[]); + + /** + * Reports type names of the columns of the query result. + * This is available from SQLite 2.6.0 on and needs + * the PRAGMA show_datatypes to be turned on.<BR><BR> + * + * @param types string array holding column types + */ + + public void types(String types[]); + + /** + * Reports row data of the query result. + * This method is invoked for each row of the + * result set. If true is returned the running + * SQLite query is aborted.<BR><BR> + * + * @param rowdata string array holding the column values of the row + */ + + public boolean newrow(String rowdata[]); +} diff --git a/sql/src/main/java/SQLite/Constants.java b/sql/src/main/java/SQLite/Constants.java new file mode 100644 index 0000000..4e636b9 --- /dev/null +++ b/sql/src/main/java/SQLite/Constants.java @@ -0,0 +1,157 @@ +/* DO NOT EDIT */ + +package SQLite; + +/** + * Container for SQLite constants. + */ + +public final class Constants { + /* + * Error code: 0 + */ + public static final int SQLITE_OK = 0; + /* + * Error code: 1 + */ + public static final int SQLITE_ERROR = 1; + /* + * Error code: 2 + */ + public static final int SQLITE_INTERNAL = 2; + /* + * Error code: 3 + */ + public static final int SQLITE_PERM = 3; + /* + * Error code: 4 + */ + public static final int SQLITE_ABORT = 4; + /* + * Error code: 5 + */ + public static final int SQLITE_BUSY = 5; + /* + * Error code: 6 + */ + public static final int SQLITE_LOCKED = 6; + /* + * Error code: 7 + */ + public static final int SQLITE_NOMEM = 7; + /* + * Error code: 8 + */ + public static final int SQLITE_READONLY = 8; + /* + * Error code: 9 + */ + public static final int SQLITE_INTERRUPT = 9; + /* + * Error code: 10 + */ + public static final int SQLITE_IOERR = 10; + /* + * Error code: 11 + */ + public static final int SQLITE_CORRUPT = 11; + /* + * Error code: 12 + */ + public static final int SQLITE_NOTFOUND = 12; + /* + * Error code: 13 + */ + public static final int SQLITE_FULL = 13; + /* + * Error code: 14 + */ + public static final int SQLITE_CANTOPEN = 14; + /* + * Error code: 15 + */ + public static final int SQLITE_PROTOCOL = 15; + /* + * Error code: 16 + */ + public static final int SQLITE_EMPTY = 16; + /* + * Error code: 17 + */ + public static final int SQLITE_SCHEMA = 17; + /* + * Error code: 18 + */ + public static final int SQLITE_TOOBIG = 18; + /* + * Error code: 19 + */ + public static final int SQLITE_CONSTRAINT = 19; + /* + * Error code: 20 + */ + public static final int SQLITE_MISMATCH = 20; + /* + * Error code: 21 + */ + public static final int SQLITE_MISUSE = 21; + /* + * Error code: 22 + */ + public static final int SQLITE_NOLFS = 22; + /* + * Error code: 23 + */ + public static final int SQLITE_AUTH = 23; + /* + * Error code: 24 + */ + public static final int SQLITE_FORMAT = 24; + /* + * Error code: 25 + */ + public static final int SQLITE_RANGE = 25; + /* + * Error code: 26 + */ + public static final int SQLITE_NOTADB = 26; + public static final int SQLITE_ROW = 100; + public static final int SQLITE_DONE = 101; + public static final int SQLITE_INTEGER = 1; + public static final int SQLITE_FLOAT = 2; + public static final int SQLITE_BLOB = 4; + public static final int SQLITE_NULL = 5; + public static final int SQLITE3_TEXT = 3; + public static final int SQLITE_NUMERIC = -1; + public static final int SQLITE_TEXT = 3; + public static final int SQLITE2_TEXT = -2; + public static final int SQLITE_ARGS = -3; + public static final int SQLITE_COPY = 0; + public static final int SQLITE_CREATE_INDEX = 1; + public static final int SQLITE_CREATE_TABLE = 2; + public static final int SQLITE_CREATE_TEMP_INDEX = 3; + public static final int SQLITE_CREATE_TEMP_TABLE = 4; + public static final int SQLITE_CREATE_TEMP_TRIGGER = 5; + public static final int SQLITE_CREATE_TEMP_VIEW = 6; + public static final int SQLITE_CREATE_TRIGGER = 7; + public static final int SQLITE_CREATE_VIEW = 8; + public static final int SQLITE_DELETE = 9; + public static final int SQLITE_DROP_INDEX = 10; + public static final int SQLITE_DROP_TABLE = 11; + public static final int SQLITE_DROP_TEMP_INDEX = 12; + public static final int SQLITE_DROP_TEMP_TABLE = 13; + public static final int SQLITE_DROP_TEMP_TRIGGER = 14; + public static final int SQLITE_DROP_TEMP_VIEW = 15; + public static final int SQLITE_DROP_TRIGGER = 16; + public static final int SQLITE_DROP_VIEW = 17; + public static final int SQLITE_INSERT = 18; + public static final int SQLITE_PRAGMA = 19; + public static final int SQLITE_READ = 20; + public static final int SQLITE_SELECT = 21; + public static final int SQLITE_TRANSACTION = 22; + public static final int SQLITE_UPDATE = 23; + public static final int SQLITE_ATTACH = 24; + public static final int SQLITE_DETACH = 25; + public static final int SQLITE_DENY = 1; + public static final int SQLITE_IGNORE = 2; +} diff --git a/sql/src/main/java/SQLite/Database.java b/sql/src/main/java/SQLite/Database.java new file mode 100644 index 0000000..dcaaf9d --- /dev/null +++ b/sql/src/main/java/SQLite/Database.java @@ -0,0 +1,615 @@ +package SQLite; + +/** + * Main class wrapping an SQLite database. + */ + +public class Database { + + /** + * Internal handle for the native SQLite API. + */ + + protected long handle = 0; + + /** + * Internal last error code for exec() methods. + */ + + protected int error_code = 0; + + /** + * Open an SQLite database file. + * + * @param filename the name of the database file + * @param mode open mode, currently ignored + */ + + public void open(String filename, int mode) throws SQLite.Exception { + synchronized(this) { + _open(filename, mode); + } + } + + private native void _open(String filename, int mode) + throws SQLite.Exception; + + /** + * Open SQLite auxiliary database file for temporary + * tables. + * + * @param filename the name of the auxiliary file or null + */ + + public void open_aux_file(String filename) throws SQLite.Exception { + synchronized(this) { + _open_aux_file(filename); + } + } + + private native void _open_aux_file(String filename) + throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected void finalize() { + synchronized(this) { + _finalize(); + } + } + + private native void _finalize(); + + /** + * Close the underlying SQLite database file. + */ + + public void close() throws SQLite.Exception { + synchronized(this) { + _close(); + } + } + + private native void _close() + throws SQLite.Exception; + + /** + * Execute an SQL statement and invoke callback methods + * for each row of the result set.<P> + * + * It the method fails, an SQLite.Exception is thrown and + * an error code is set, which later can be retrieved by + * the last_error() method. + * + * @param sql the SQL statement to be executed + * @param cb the object implementing the callback methods + */ + + public void exec(String sql, SQLite.Callback cb) throws SQLite.Exception { + synchronized(this) { + _exec(sql, cb); + } + } + + private native void _exec(String sql, SQLite.Callback cb) + throws SQLite.Exception; + + /** + * Execute an SQL statement and invoke callback methods + * for each row of the result set. Each '%q' or %Q in the + * statement string is substituted by its corresponding + * element in the argument vector. + * <BR><BR> + * Example:<BR> + * <PRE> + * String args[] = new String[1]; + * args[0] = "tab%"; + * db.exec("select * from sqlite_master where type like '%q'", + * null, args); + * </PRE> + * + * It the method fails, an SQLite.Exception is thrown and + * an error code is set, which later can be retrieved by + * the last_error() method. + * + * @param sql the SQL statement to be executed + * @param cb the object implementing the callback methods + * @param args arguments for the SQL statement, '%q' substitution + */ + + public void exec(String sql, SQLite.Callback cb, + String args[]) throws SQLite.Exception { + synchronized(this) { + _exec(sql, cb, args); + } + } + + private native void _exec(String sql, SQLite.Callback cb, String args[]) + throws SQLite.Exception; + + /** + * Return the row identifier of the last inserted + * row. + */ + + public long last_insert_rowid() { + synchronized(this) { + return _last_insert_rowid(); + } + } + + private native long _last_insert_rowid(); + + /** + * Abort the current SQLite operation. + */ + + public void interrupt() { + synchronized(this) { + _interrupt(); + } + } + + private native void _interrupt(); + + /** + * Return the number of changed rows for the last statement. + */ + + public long changes() { + synchronized(this) { + return _changes(); + } + } + + private native long _changes(); + + /** + * Establish a busy callback method which gets called when + * an SQLite table is locked. + * + * @param bh the object implementing the busy callback method + */ + + public void busy_handler(SQLite.BusyHandler bh) { + synchronized(this) { + _busy_handler(bh); + } + } + + private native void _busy_handler(SQLite.BusyHandler bh); + + /** + * Set the timeout for waiting for an SQLite table to become + * unlocked. + * + * @param ms number of millisecond to wait + */ + + public void busy_timeout(int ms) { + synchronized(this) { + _busy_timeout(ms); + } + } + + private native void _busy_timeout(int ms); + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @return result set + */ + + public TableResult get_table(String sql) throws SQLite.Exception { + TableResult ret = new TableResult(); + if (!is3()) { + exec(sql, ret); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql); + set_last_error(vm.error_code); + while (vm.step(ret)) { + set_last_error(vm.error_code); + } + vm.finalize(); + } + } + return ret; + } + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @param args arguments for the SQL statement, '%q' substitution + * @return result set + */ + + public TableResult get_table(String sql, String args[]) + throws SQLite.Exception { + TableResult ret = new TableResult(); + if (!is3()) { + exec(sql, ret, args); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql, args); + set_last_error(vm.error_code); + while (vm.step(ret)) { + set_last_error(vm.error_code); + } + vm.finalize(); + } + } + return ret; + } + + /** + * Convenience method to retrieve an entire result + * set into memory. + * + * @param sql the SQL statement to be executed + * @param args arguments for the SQL statement, '%q' substitution + * @param tbl TableResult to receive result set + * @return result set + */ + + public void get_table(String sql, String args[], TableResult tbl) + throws SQLite.Exception { + tbl.clear(); + if (!is3()) { + exec(sql, tbl, args); + } else { + synchronized(this) { + /* only one statement !!! */ + Vm vm = compile(sql, args); + while (vm.step(tbl)) { + } + vm.finalize(); + } + } + } + + /** + * See if an SQL statement is complete. + * Returns true if the input string comprises + * one or more complete SQL statements. + * + * @param sql the SQL statement to be checked + */ + + public synchronized static boolean complete(String sql) { + return _complete(sql); + } + + private native static boolean _complete(String sql); + + /** + * Return SQLite version number as string. + * Don't rely on this when both SQLite 2 and 3 are compiled + * into the native part. Use the class method in this case. + */ + + public native static String version(); + + /** + * Return SQLite version number as string. + * If the database is not open, <tt>unknown</tt> is returned. + */ + + public native String dbversion(); + + /** + * Create regular function. + * + * @param name the name of the new function + * @param nargs number of arguments to function + * @param f interface of function + */ + + public void create_function(String name, int nargs, Function f) { + synchronized(this) { + _create_function(name, nargs, f); + } + } + + private native void _create_function(String name, int nargs, Function f); + + /** + * Create aggregate function. + * + * @param name the name of the new function + * @param nargs number of arguments to function + * @param f interface of function + */ + + public void create_aggregate(String name, int nargs, Function f) { + synchronized(this) { + _create_aggregate(name, nargs, f); + } + } + + private native void _create_aggregate(String name, int nargs, Function f); + + /** + * Set function return type. Only available in SQLite 2.6.0 and + * above, otherwise a no-op. + * + * @param name the name of the function whose return type is to be set + * @param type return type code, e.g. SQLite.Constants.SQLITE_NUMERIC + */ + + public void function_type(String name, int type) { + synchronized(this) { + _function_type(name, type); + } + } + + private native void _function_type(String name, int type); + + /** + * Return the code of the last error occured in + * any of the exec() methods. The value is valid + * after an Exception has been reported by one of + * these methods. See the <A HREF="Constants.html">Constants</A> + * class for possible values. + * + * @return SQLite error code + */ + + public int last_error() { + return error_code; + } + + /** + * Internal: set error code. + * @param error_code new error code + */ + + protected void set_last_error(int error_code) { + this.error_code = error_code; + } + + /** + * Return last error message of SQLite3 engine. + * + * @return error string or null + */ + + public String error_message() { + synchronized(this) { + return _errmsg(); + } + } + + private native String _errmsg(); + + /** + * Return error string given SQLite error code (SQLite2). + * + * @param error_code the error code + * @return error string + */ + + public static native String error_string(int error_code); + + /** + * Set character encoding. + * @param enc name of encoding + */ + + public void set_encoding(String enc) throws SQLite.Exception { + synchronized(this) { + _set_encoding(enc); + } + } + + private native void _set_encoding(String enc) + throws SQLite.Exception; + + /** + * Set authorizer function. Only available in SQLite 2.7.6 and + * above, otherwise a no-op. + * + * @param auth the authorizer function + */ + + public void set_authorizer(Authorizer auth) { + synchronized(this) { + _set_authorizer(auth); + } + } + + private native void _set_authorizer(Authorizer auth); + + /** + * Set trace function. Only available in SQLite 2.7.6 and above, + * otherwise a no-op. + * + * @param tr the trace function + */ + + public void trace(Trace tr) { + synchronized(this) { + _trace(tr); + } + } + + private native void _trace(Trace tr); + + /** + * Compile and return SQLite VM for SQL statement. Only available + * in SQLite 2.8.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be compiled + * @return a Vm object + */ + + public Vm compile(String sql) throws SQLite.Exception { + synchronized(this) { + Vm vm = new Vm(); + vm_compile(sql, vm); + return vm; + } + } + + /** + * Compile and return SQLite VM for SQL statement. Only available + * in SQLite 3.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be compiled + * @param args arguments for the SQL statement, '%q' substitution + * @return a Vm object + */ + + public Vm compile(String sql, String args[]) throws SQLite.Exception { + synchronized(this) { + Vm vm = new Vm(); + vm_compile_args(sql, vm, args); + return vm; + } + } + + /** + * Prepare and return SQLite3 statement for SQL. Only available + * in SQLite 3.0 and above, otherwise a no-op. + * + * @param sql SQL statement to be prepared + * @return a Stmt object + */ + + public Stmt prepare(String sql) throws SQLite.Exception { + synchronized(this) { + Stmt stmt = new Stmt(); + stmt_prepare(sql, stmt); + return stmt; + } + } + + /** + * Open an SQLite3 blob. Only available in SQLite 3.4.0 and above. + * @param db database name + * @param table table name + * @param column column name + * @param row row identifier + * @param rw if true, open for read-write, else read-only + * @return a Blob object + */ + + public Blob open_blob(String db, String table, String column, + long row, boolean rw) throws SQLite.Exception { + synchronized(this) { + Blob blob = new Blob(); + _open_blob(db, table, column, row, rw, blob); + return blob; + } + } + + /** + * Check type of open database. + * @return true if SQLite3 database + */ + + public native boolean is3(); + + /** + * Internal compile method. + * @param sql SQL statement + * @param vm Vm object + */ + + private native void vm_compile(String sql, Vm vm) + throws SQLite.Exception; + + /** + * Internal compile method, SQLite 3.0 only. + * @param sql SQL statement + * @param args arguments for the SQL statement, '%q' substitution + * @param vm Vm object + */ + + private native void vm_compile_args(String sql, Vm vm, String args[]) + throws SQLite.Exception; + + /** + * Internal SQLite3 prepare method. + * @param sql SQL statement + * @param stmt Stmt object + */ + + private native void stmt_prepare(String sql, Stmt stmt) + throws SQLite.Exception; + + /** + * Internal SQLite open blob method. + * @param db database name + * @param table table name + * @param column column name + * @param row row identifier + * @param rw if true, open for read-write, else read-only + * @param blob Blob object + */ + + private native void _open_blob(String db, String table, String column, + long row, boolean rw, Blob blob) + throws SQLite.Exception; + + /** + * Establish a progress callback method which gets called after + * N SQLite VM opcodes. + * + * @param n number of SQLite VM opcodes until callback is invoked + * @param p the object implementing the progress callback method + */ + + public void progress_handler(int n, SQLite.ProgressHandler p) { + synchronized(this) { + _progress_handler(n, p); + } + } + + private native void _progress_handler(int n, SQLite.ProgressHandler p); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + /** + * Static initializer to load the native part. + */ + + static { + try { +// String path = System.getProperty("SQLite.library.path"); +// if (path == null || path.length() == 0){ +// System.loadLibrary("sqlite_jni"); +// } else { +// try { +// java.lang.reflect.Method mapLibraryName; +// Class param[] = new Class[1]; +// param[0] = String.class; +// mapLibraryName = System.class.getMethod("mapLibraryName", +// param); +// Object args[] = new Object[1]; +// args[0] = "sqlite_jni"; +// String mapped = (String) mapLibraryName.invoke(null, args); +// System.load(path + java.io.File.separator + mapped); +// } catch (Throwable t) { +// System.loadLibrary("sqlite_jni"); +// } +// } + internal_init(); + } catch (Throwable t) { + System.err.println("Unable to load sqlite: " + t); + } + } +} + diff --git a/sql/src/main/java/SQLite/Exception.java b/sql/src/main/java/SQLite/Exception.java new file mode 100644 index 0000000..cc26b99 --- /dev/null +++ b/sql/src/main/java/SQLite/Exception.java @@ -0,0 +1,18 @@ +package SQLite; + +/** + * Class for SQLite related exceptions. + */ + +public class Exception extends java.lang.Exception { + + /** + * Construct a new SQLite exception. + * + * @param string error message + */ + + public Exception(String string) { + super(string); + } +} diff --git a/sql/src/main/java/SQLite/Function.java b/sql/src/main/java/SQLite/Function.java new file mode 100644 index 0000000..5aa5e33 --- /dev/null +++ b/sql/src/main/java/SQLite/Function.java @@ -0,0 +1,59 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined functions. + * Each callback method receives a + * <A HREF="FunctionContext.html">FunctionContext</A> object + * which is used to set the function result or error code. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * class SinFunc implements SQLite.Function { + * public void function(SQLite.FunctionContext fc, String args[]) { + * try { + * Double d = new Double(args[0]); + * fc.set_result(Math.sin(d.doubleValue())); + * } catch (Exception e) { + * fc.set_error("sin(" + args[0] + "):" + e); + * } + * } + * ... + * } + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * db.create_function("sin", 1, SinFunc); + * ... + * db.exec("select sin(1.0) from test", null); + * </PRE> + */ + +public interface Function { + + /** + * Callback for regular function. + * + * @param fc function's context for reporting result + * @param args String array of arguments + */ + + public void function(FunctionContext fc, String args[]); + + /** + * Callback for one step in aggregate function. + * + * @param fc function's context for reporting result + * @param args String array of arguments + */ + + public void step(FunctionContext fc, String args[]); + + /** + * Callback for final step in aggregate function. + * + * @param fc function's context for reporting result + */ + + public void last_step(FunctionContext fc); + +} diff --git a/sql/src/main/java/SQLite/FunctionContext.java b/sql/src/main/java/SQLite/FunctionContext.java new file mode 100644 index 0000000..d0b5182 --- /dev/null +++ b/sql/src/main/java/SQLite/FunctionContext.java @@ -0,0 +1,82 @@ +package SQLite; + +/** + * Context for execution of SQLite's user defined functions. + * A reference to an instance of this class is passed to + * user defined functions. + */ + +public class FunctionContext { + + /** + * Internal handle for the native SQLite API. + */ + + private long handle = 0; + + /** + * Set function result from string. + * + * @param r result string + */ + + public native void set_result(String r); + + /** + * Set function result from integer. + * + * @param r result integer + */ + + public native void set_result(int r); + + /** + * Set function result from double. + * + * @param r result double + */ + + public native void set_result(double r); + + /** + * Set function result from error message. + * + * @param r result string (error message) + */ + + public native void set_error(String r); + + /** + * Set function result from byte array. + * Only provided by SQLite3 databases. + * + * @param r result byte array + */ + + public native void set_result(byte[] r); + + /** + * Set function result as empty blob given size. + * Only provided by SQLite3 databases. + * + * @param n size for empty blob + */ + + public native void set_result_zeroblob(int n); + + /** + * Retrieve number of rows for aggregate function. + */ + + public native int count(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCConnection.java b/sql/src/main/java/SQLite/JDBC2y/JDBCConnection.java new file mode 100644 index 0000000..20c98e3 --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCConnection.java @@ -0,0 +1,452 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.*; + +public class JDBCConnection + implements java.sql.Connection, SQLite.BusyHandler { + + /** + * Open database. + */ + protected DatabaseX db; + + /** + * Database URL. + */ + protected String url; + + /** + * Character encoding. + */ + protected String enc; + + /** + * Autocommit flag, true means autocommit. + */ + protected boolean autocommit = true; + + /** + * In-transaction flag. + * Can be true only when autocommit false. + */ + protected boolean intrans = false; + + /** + * Timeout for Database.exec() + */ + protected int timeout = 1000000; + + /** + * File name of database. + */ + private String dbfile = null; + + /** + * Reference to meta data or null. + */ + private JDBCDatabaseMetaData meta = null; + + /** + * Base time value for timeout handling. + */ + private long t0; + + /** + * Database in readonly mode. + */ + private boolean readonly = false; + + + private boolean busy0(DatabaseX db, int count) { + if (count <= 1) { + t0 = System.currentTimeMillis(); + } + if (db != null) { + long t1 = System.currentTimeMillis(); + if (t1 - t0 > timeout) { + return false; + } + db.wait(100); + return true; + } + return false; + } + + public boolean busy(String table, int count) { + return busy0(db, count); + } + + protected boolean busy3(DatabaseX db, int count) { + if (count <= 1) { + t0 = System.currentTimeMillis(); + } + if (db != null) { + long t1 = System.currentTimeMillis(); + if (t1 - t0 > timeout) { + return false; + } + return true; + } + return false; + } + + private DatabaseX open(boolean readonly) throws SQLException { + DatabaseX db = null; + try { + db = new DatabaseX(); + db.open(dbfile, readonly ? 0444 : 0644); + db.set_encoding(enc); + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + int loop = 0; + while (true) { + try { + db.exec("PRAGMA short_column_names = off;", null); + db.exec("PRAGMA full_column_names = on;", null); + db.exec("PRAGMA empty_result_callbacks = on;", null); + if (SQLite.Database.version().compareTo("2.6.0") >= 0) { + db.exec("PRAGMA show_datatypes = on;", null); + } + } catch (SQLite.Exception e) { + if (db.last_error() != SQLite.Constants.SQLITE_BUSY || + !busy0(db, ++loop)) { + try { + db.close(); + } catch (SQLite.Exception ee) { + } + throw new SQLException(e.toString()); + } + continue; + } + break; + } + return db; + } + + public JDBCConnection(String url, String enc) throws SQLException { + if (url.startsWith("sqlite:/")) { + dbfile = url.substring(8); + } else if (url.startsWith("jdbc:sqlite:/")) { + dbfile = url.substring(13); + } else { + throw new SQLException("unsupported url"); + } + this.url = url; + this.enc = enc; + try { + db = open(readonly); + db.busy_handler(this); + } catch (SQLException e) { + if (db != null) { + try { + db.close(); + } catch (SQLite.Exception ee) { + } + } + throw e; + } + } + + /* non-standard */ + public SQLite.Database getSQLiteDatabase() { + return (SQLite.Database) db; + } + + public Statement createStatement() { + JDBCStatement s = new JDBCStatement(this); + return s; + } + + public Statement createStatement(int resultSetType, + int resultSetConcurrency) + throws SQLException { + JDBCStatement s = new JDBCStatement(this); + return s; + } + + public DatabaseMetaData getMetaData() throws SQLException { + if (meta == null) { + meta = new JDBCDatabaseMetaData(this); + } + return meta; + } + + public void close() throws SQLException { + try { + rollback(); + } catch (SQLException e) { + /* ignored */ + } + intrans = false; + if (db != null) { + try { + db.close(); + db = null; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + } + + public boolean isClosed() throws SQLException { + return db == null; + } + + public boolean isReadOnly() throws SQLException { + return readonly; + } + + public void clearWarnings() throws SQLException { + } + + public void commit() throws SQLException { + if (db == null) { + throw new SQLException("stale connection"); + } + if (!intrans) { + return; + } + try { + db.exec("COMMIT", null); + intrans = false; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + + public boolean getAutoCommit() throws SQLException { + return autocommit; + } + + public String getCatalog() throws SQLException { + return null; + } + + public int getTransactionIsolation() throws SQLException { + return TRANSACTION_SERIALIZABLE; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public String nativeSQL(String sql) throws SQLException { + throw new SQLException("not supported"); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + throw new SQLException("not supported"); + } + + public CallableStatement prepareCall(String sql, int x, int y) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql); + return s; + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency) + throws SQLException { + JDBCPreparedStatement s = new JDBCPreparedStatement(this, sql); + return s; + } + + public void rollback() throws SQLException { + if (db == null) { + throw new SQLException("stale connection"); + } + if (!intrans) { + return; + } + try { + db.exec("ROLLBACK", null); + intrans = false; + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + + public void setAutoCommit(boolean ac) throws SQLException { + if (ac && intrans && db != null) { + try { + db.exec("ROLLBACK", null); + } catch (SQLite.Exception e) { + throw new SQLException(e.toString()); + } + } + intrans = false; + autocommit = ac; + } + + public void setCatalog(String catalog) throws SQLException { + } + + public void setReadOnly(boolean ro) throws SQLException { + if (intrans) { + throw new SQLException("incomplete transaction"); + } + if (ro != readonly) { + DatabaseX db = null; + try { + db = open(ro); + this.db.close(); + this.db = db; + db = null; + readonly = ro; + } catch (SQLException e) { + throw e; + } catch (SQLite.Exception ee) { + if (db != null) { + try { + db.close(); + } catch (SQLite.Exception eee) { + } + } + throw new SQLException(ee.toString()); + } + } + } + + public void setTransactionIsolation(int level) throws SQLException { + if (level != TRANSACTION_SERIALIZABLE) { + throw new SQLException("not supported"); + } + } + + public java.util.Map<String, Class<?>> getTypeMap() throws SQLException { + throw new SQLException("not supported"); + } + + public void setTypeMap(java.util.Map map) throws SQLException { + throw new SQLException("not supported"); + } + + public int getHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + + public void setHoldability(int holdability) throws SQLException { + if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) { + return; + } + throw new SQLException("not supported"); + } + + public Savepoint setSavepoint() throws SQLException { + throw new SQLException("not supported"); + } + + public Savepoint setSavepoint(String name) throws SQLException { + throw new SQLException("not supported"); + } + + public void rollback(Savepoint x) throws SQLException { + throw new SQLException("not supported"); + } + + public void releaseSavepoint(Savepoint x) throws SQLException { + throw new SQLException("not supported"); + } + + public Statement createStatement(int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) + throws SQLException { + if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) { + throw new SQLException("not supported"); + } + return createStatement(resultSetType, resultSetConcurrency); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) + throws SQLException { + if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) { + throw new SQLException("not supported"); + } + return prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + public CallableStatement prepareCall(String sql, int x, int y, int z) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return prepareStatement(sql); + } + + public PreparedStatement prepareStatement(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public PreparedStatement prepareStatement(String sql, String columns[]) + throws SQLException { + throw new SQLException("not supported"); + } + +} + +class DatabaseX extends SQLite.Database { + + static Object lock = new Object(); + + public DatabaseX() { + super(); + } + + void wait(int ms) { + try { + synchronized (lock) { + lock.wait(ms); + } + } catch (java.lang.Exception e) { + } + } + + public void exec(String sql, SQLite.Callback cb) + throws SQLite.Exception { + super.exec(sql, cb); + synchronized (lock) { + lock.notifyAll(); + } + } + + public void exec(String sql, SQLite.Callback cb, String args[]) + throws SQLite.Exception { + super.exec(sql, cb, args); + synchronized (lock) { + lock.notifyAll(); + } + } + + public SQLite.TableResult get_table(String sql, String args[]) + throws SQLite.Exception { + SQLite.TableResult ret = super.get_table(sql, args); + synchronized (lock) { + lock.notifyAll(); + } + return ret; + } + + public void get_table(String sql, String args[], SQLite.TableResult tbl) + throws SQLite.Exception { + super.get_table(sql, args, tbl); + synchronized (lock) { + lock.notifyAll(); + } + } + +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java b/sql/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java new file mode 100644 index 0000000..8c14d1d --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java @@ -0,0 +1,1578 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.Hashtable; + +public class JDBCDatabaseMetaData implements DatabaseMetaData { + + private JDBCConnection conn; + + public JDBCDatabaseMetaData(JDBCConnection conn) { + this.conn = conn; + } + + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + public boolean allTablesAreSelectable() throws SQLException { + return true; + } + + public String getURL() throws SQLException { + return conn.url; + } + + public String getUserName() throws SQLException { + return ""; + } + + public boolean isReadOnly() throws SQLException { + return false; + } + + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + public boolean nullsAreSortedLow() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + public String getDatabaseProductName() throws SQLException { + return "SQLite"; + } + + public String getDatabaseProductVersion() throws SQLException { + return SQLite.Database.version(); + } + + public String getDriverName() throws SQLException { + return "SQLite/JDBC"; + } + + public String getDriverVersion() throws SQLException { + return "" + SQLite.JDBCDriver.MAJORVERSION + "." + + SQLite.JDBCDriver.MINORVERSION; + } + + public int getDriverMajorVersion() { + return SQLite.JDBCDriver.MAJORVERSION; + } + + public int getDriverMinorVersion() { + return SQLite.JDBCDriver.MINORVERSION; + } + + public boolean usesLocalFiles() throws SQLException { + return true; + } + + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + return true; + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return true; + } + + public String getIdentifierQuoteString() throws SQLException { + return "\""; + } + + public String getSQLKeywords() throws SQLException { + return "SELECT,UPDATE,CREATE,TABLE,VIEW,DELETE,FROM,WHERE" + + ",COMMIT,ROLLBACK,TRIGGER"; + } + + public String getNumericFunctions() throws SQLException { + return ""; + } + + public String getStringFunctions() throws SQLException { + return ""; + } + + public String getSystemFunctions() throws SQLException { + return ""; + } + + public String getTimeDateFunctions() throws SQLException { + return ""; + } + + public String getSearchStringEscape() throws SQLException { + return "\\"; + } + + public String getExtraNameCharacters() throws SQLException { + return ""; + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + public boolean supportsConvert() throws SQLException { + return false; + } + + public boolean supportsConvert(int fromType, int toType) + throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return true; + } + + public boolean supportsDifferentTableCorrelationNames() + throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return true; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return true; + } + + public boolean supportsGroupBy() throws SQLException { + return true; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return true; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsLikeEscapeClause() throws SQLException { + return false; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + public boolean supportsNonNullableColumns() throws SQLException { + return true; + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + return true; + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return true; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + public boolean supportsIntegrityEnhancementFacility() + throws SQLException { + return false; + } + + public boolean supportsOuterJoins() throws SQLException { + return false; + } + + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } + + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } + + public String getSchemaTerm() throws SQLException { + return ""; + } + + public String getProcedureTerm() throws SQLException { + return ""; + } + + public String getCatalogTerm() throws SQLException { + return ""; + } + + public boolean isCatalogAtStart() throws SQLException { + return false; + } + + public String getCatalogSeparator() throws SQLException { + return ""; + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInPrivilegeDefinitions() + throws SQLException { + return false; + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInPrivilegeDefinitions() + throws SQLException { + return false; + } + + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public boolean supportsSelectForUpdate() throws SQLException { + return true; + } + + public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInExists() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInIns() throws SQLException { + return true; + } + + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } + + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } + + public boolean supportsUnion() throws SQLException { + return false; + } + + public boolean supportsUnionAll() throws SQLException { + return false; + } + + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + public int getMaxConnections() throws SQLException { + return 0; + } + + public int getMaxCursorNameLength() throws SQLException { + return 8; + } + + public int getMaxIndexLength() throws SQLException { + return 0; + } + + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + public int getMaxRowSize() throws SQLException { + return 0; + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return true; + } + + public int getMaxStatementLength() throws SQLException { + return 0; + } + + public int getMaxStatements() throws SQLException { + return 0; + } + + public int getMaxTableNameLength() throws SQLException { + return 0; + } + + public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + public int getMaxUserNameLength() throws SQLException { + return 0; + } + + public int getDefaultTransactionIsolation() throws SQLException { + return Connection.TRANSACTION_SERIALIZABLE; + } + + public boolean supportsTransactions() throws SQLException { + return true; + } + + public boolean supportsTransactionIsolationLevel(int level) + throws SQLException { + return level == Connection.TRANSACTION_SERIALIZABLE; + } + + public boolean supportsDataDefinitionAndDataManipulationTransactions() + throws SQLException { + return true; + } + + public boolean supportsDataManipulationTransactionsOnly() + throws SQLException { + return false; + } + + public boolean dataDefinitionCausesTransactionCommit() + throws SQLException { + return false; + } + + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + public ResultSet getProcedures(String catalog, String schemaPattern, + String procedureNamePattern) + throws SQLException { + return null; + } + + public ResultSet getProcedureColumns(String catalog, + String schemaPattern, + String procedureNamePattern, + String columnNamePattern) + throws SQLException { + return null; + } + + public ResultSet getTables(String catalog, String schemaPattern, + String tableNamePattern, String types[]) + throws SQLException { + JDBCStatement s = new JDBCStatement(conn); + StringBuffer sb = new StringBuffer(); + sb.append("SELECT '' AS 'TABLE_CAT', " + + "'' AS 'TABLE_SCHEM', " + + "tbl_name AS 'TABLE_NAME', " + + "upper(type) AS 'TABLE_TYPE', " + + "'' AS REMARKS FROM sqlite_master " + + "WHERE tbl_name like "); + if (tableNamePattern != null) { + sb.append(SQLite.Shell.sql_quote(tableNamePattern)); + } else { + sb.append("'%'"); + } + sb.append(" AND "); + if (types == null || types.length == 0) { + sb.append("(type = 'table' or type = 'view')"); + } else { + sb.append("("); + String sep = ""; + for (int i = 0; i < types.length; i++) { + sb.append(sep); + sb.append("type = "); + sb.append(SQLite.Shell.sql_quote(types[i].toLowerCase())); + sep = " or "; + } + sb.append(")"); + } + ResultSet rs = null; + try { + rs = s.executeQuery(sb.toString()); + s.close(); + } catch (SQLException e) { + throw e; + } finally { + s.close(); + } + return rs; + } + + public ResultSet getSchemas() throws SQLException { + String cols[] = { "TABLE_SCHEM" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = { "" }; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getCatalogs() throws SQLException { + String cols[] = { "TABLE_CAT" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = { "" }; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getTableTypes() throws SQLException { + String cols[] = { "TABLE_TYPE" }; + SQLite.TableResult tr = new SQLite.TableResult(); + tr.columns(cols); + String row[] = new String[1]; + row[0] = "TABLE"; + tr.newrow(row); + row = new String[1]; + row[0] = "VIEW"; + tr.newrow(row); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return (ResultSet) rs; + } + + public ResultSet getColumns(String catalog, String schemaPattern, + String tableNamePattern, + String columnNamePattern) + throws SQLException { + JDBCStatement s = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(tableNamePattern) + + ")")); + s.close(); + } catch (SQLException e) { + throw e; + } finally { + s.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_POINTS", + "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT, Types.VARCHAR, + Types.INTEGER, Types.INTEGER, Types.INTEGER, + Types.INTEGER, Types.INTEGER, Types.VARCHAR, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.INTEGER, Types.INTEGER, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h.put(rs0.tr.column[i], new Integer(i)); + } + if (columnNamePattern != null && + columnNamePattern.charAt(0) == '%') { + columnNamePattern = null; + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h.get("name")).intValue(); + if (columnNamePattern != null) { + if (r0[col].compareTo(columnNamePattern) != 0) { + continue; + } + } + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = tableNamePattern; + row[3] = r0[col]; + col = ((Integer) h.get("type")).intValue(); + String typeStr = r0[col]; + int type = mapSqlType(typeStr); + row[4] = "" + type; + row[5] = mapTypeName(type); + row[6] = "" + getD(typeStr, type); + row[7] = "" + getM(typeStr, type); + row[8] = "10"; + row[9] = "0"; + row[11] = null; + col = ((Integer) h.get("dflt_value")).intValue(); + row[12] = r0[col]; + row[13] = "0"; + row[14] = "0"; + row[15] = "65536"; + col = ((Integer) h.get("cid")).intValue(); + Integer cid = new Integer(r0[col]); + row[16] = "" + (cid.intValue() + 1); + col = ((Integer) h.get("notnull")).intValue(); + row[17] = (r0[col].charAt(0) == '0') ? "YES" : "NO"; + row[10] = (r0[col].charAt(0) == '0') ? "" + columnNullable : + "" + columnNoNulls; + tr.newrow(row); + } + } + return rs; + } + + public ResultSet getColumnPrivileges(String catalog, String schema, + String table, + String columnNamePattern) + throws SQLException { + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "GRANTOR", "GRANTEE", + "PRIVILEGE", "IS_GRANTABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getTablePrivileges(String catalog, String schemaPattern, + String tableNamePattern) + throws SQLException { + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "GRANTOR", "GRANTEE", + "PRIVILEGE", "IS_GRANTABLE" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getBestRowIdentifier(String catalog, String schema, + String table, int scope, + boolean nullable) + throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + s1.close(); + } + String cols[] = { + "SCOPE", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "PSEUDO_COLUMN" + }; + int types[] = { + Types.SMALLINT, Types.VARCHAR, Types.SMALLINT, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.SMALLINT, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0 && + rs1 != null && rs1.tr != null && rs1.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + Hashtable<String, Integer> h1 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs1.tr.ncolumns; i++) { + h1.put(rs1.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s2 = new JDBCStatement(conn); + JDBCResultSet rs2 = null; + try { + rs2 = (JDBCResultSet) + (s2.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s2.close(); + } + if (rs2 == null || rs2.tr == null || rs2.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h2 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs2.tr.ncolumns; k++) { + h2.put(rs2.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs2.tr.nrows; k++) { + String r2[] = (String [])(rs2.tr.rows.elementAt(k)); + col = ((Integer) h2.get("name")).intValue(); + String cname = r2[col]; + for (int m = 0; m < rs1.tr.nrows; m++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(m)); + col = ((Integer) h1.get("name")).intValue(); + if (cname.compareTo(r1[col]) == 0) { + String row[] = new String[cols.length]; + row[0] = "" + scope; + row[1] = cname; + row[2] = "" + Types.VARCHAR; + row[3] = "VARCHAR"; + row[4] = "65536"; + row[5] = "0"; + row[6] = "0"; + row[7] = "" + bestRowNotPseudo; + tr.newrow(row); + } + } + } + } + } + if (tr.nrows <= 0) { + String row[] = new String[cols.length]; + row[0] = "" + scope; + row[1] = "_ROWID_"; + row[2] = "" + Types.INTEGER; + row[3] = "INTEGER"; + row[4] = "10"; + row[5] = "0"; + row[6] = "0"; + row[7] = "" + bestRowPseudo; + tr.newrow(row); + } + return rs; + } + + public ResultSet getVersionColumns(String catalog, String schema, + String table) throws SQLException { + String cols[] = { + "SCOPE", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "PSEUDO_COLUMN" + }; + int types[] = { + Types.SMALLINT, Types.VARCHAR, Types.SMALLINT, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.SMALLINT, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + return rs; + } + + public ResultSet getPrimaryKeys(String catalog, String schema, + String table) throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "KEY_SEQ", "PK_NAME" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT, Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s1.close(); + } + if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h1 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs1.tr.ncolumns; k++) { + h1.put(rs1.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs1.tr.nrows; k++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(k)); + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + col = ((Integer) h1.get("name")).intValue(); + row[3] = r1[col]; + col = ((Integer) h1.get("seqno")).intValue(); +// BEGIN android-changed + row[4] = "" + (Integer.parseInt(r1[col]) + 1); +// END android-changed + row[5] = iname; + tr.newrow(row); + } + } + } + JDBCStatement s1 = new JDBCStatement(conn); + try { + rs0 = (JDBCResultSet) + (s1.executeQuery("PRAGMA table_info(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s1.close(); + } + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("type")).intValue(); + String type = r0[col]; + if (!type.equalsIgnoreCase("integer")) { + continue; + } + col = ((Integer) h0.get("pk")).intValue(); + String pk = r0[col]; + if (pk.charAt(0) == '0') { + continue; + } + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + col = ((Integer) h0.get("name")).intValue(); + row[3] = r0[col]; + col = ((Integer) h0.get("cid")).intValue(); +// BEGIN android-changed + row[4] = "" + (Integer.parseInt(r0[col]) + 1); +// END android-changed + row[5] = ""; + tr.newrow(row); + } + } + return rs; + } + + private void internalImportedKeys(String table, String pktable, + JDBCResultSet in, TableResultX out) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < in.tr.ncolumns; i++) { + h0.put(in.tr.column[i], new Integer(i)); + } + for (int i = 0; i < in.tr.nrows; i++) { + String r0[] = (String [])(in.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("table")).intValue(); + String pktab = r0[col]; + if (pktable != null && !pktable.equalsIgnoreCase(pktab)) { + continue; + } + col = ((Integer) h0.get("from")).intValue(); + String pkcol = r0[col]; + col = ((Integer) h0.get("to")).intValue(); + String fkcol = r0[col]; + col = ((Integer) h0.get("seq")).intValue(); + String seq = r0[col]; + String row[] = new String[out.ncolumns]; + row[0] = ""; + row[1] = ""; + row[2] = pktab; + row[3] = pkcol; + row[4] = ""; + row[5] = ""; + row[6] = table; + row[7] = fkcol == null ? pkcol : fkcol; +// BEGIN android-changed + row[8] = "" + ((Integer.parseInt(seq)) + 1); +// END android-changed + row[9] = + "" + java.sql.DatabaseMetaData.importedKeyNoAction; + row[10] = + "" + java.sql.DatabaseMetaData.importedKeyNoAction; + row[11] = null; + row[12] = null; + row[13] = + "" + java.sql.DatabaseMetaData.importedKeyNotDeferrable; + out.newrow(row); + } + } + + public ResultSet getImportedKeys(String catalog, String schema, + String table) throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA foreign_key_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + internalImportedKeys(table, null, rs0, tr); + } + return rs; + } + + public ResultSet getExportedKeys(String catalog, String schema, + String table) throws SQLException { + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + return rs; + } + + public ResultSet getCrossReference(String primaryCatalog, + String primarySchema, + String primaryTable, + String foreignCatalog, + String foreignSchema, + String foreignTable) + throws SQLException { + JDBCResultSet rs0 = null; + if (foreignTable != null && foreignTable.charAt(0) != '%') { + JDBCStatement s0 = new JDBCStatement(conn); + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA foreign_key_list(" + + SQLite.Shell.sql_quote(foreignTable) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + } + String cols[] = { + "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", + "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", + "PK_NAME", "DEFERRABILITY" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.SMALLINT + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + String pktable = null; + if (primaryTable != null && primaryTable.charAt(0) != '%') { + pktable = primaryTable; + } + internalImportedKeys(foreignTable, pktable, rs0, tr); + } + return rs; + } + + public ResultSet getTypeInfo() throws SQLException { + String cols[] = { + "TYPE_NAME", "DATA_TYPE", "PRECISION", + "LITERAL_PREFIX", "LITERAL_SUFFIX", "CREATE_PARAMS", + "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", + "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", + "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX" + }; + int types[] = { + Types.VARCHAR, Types.SMALLINT, Types.INTEGER, + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.SMALLINT, Types.BIT, Types.SMALLINT, + Types.BIT, Types.BIT, Types.BIT, + Types.VARCHAR, Types.SMALLINT, Types.SMALLINT, + Types.INTEGER, Types.INTEGER, Types.INTEGER + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + String row1[] = { + "VARCHAR", "" + Types.VARCHAR, "65536", + "'", "'", null, + "" + typeNullable, "1", "" + typeSearchable, + "0", "0", "0", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row1); + String row2[] = { + "INTEGER", "" + Types.INTEGER, "32", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row2); + String row3[] = { + "DOUBLE", "" + Types.DOUBLE, "16", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "10" + }; + tr.newrow(row3); + String row4[] = { + "FLOAT", "" + Types.FLOAT, "7", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "10" + }; + tr.newrow(row4); + String row5[] = { + "SMALLINT", "" + Types.SMALLINT, "16", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row5); + String row6[] = { + "BIT", "" + Types.BIT, "1", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "2" + }; + tr.newrow(row6); + String row7[] = { + "TIMESTAMP", "" + Types.TIMESTAMP, "30", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row7); + String row8[] = { + "DATE", "" + Types.DATE, "10", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row8); + String row9[] = { + "TIME", "" + Types.TIME, "8", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row9); + String row10[] = { + "BINARY", "" + Types.BINARY, "65536", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row10); + String row11[] = { + "VARBINARY", "" + Types.VARBINARY, "65536", + null, null, null, + "" + typeNullable, "0", "" + typeSearchable, + "0", "0", "1", + null, "0", "0", + "0", "0", "0" + }; + tr.newrow(row11); + return rs; + } + + public ResultSet getIndexInfo(String catalog, String schema, String table, + boolean unique, boolean approximate) + throws SQLException { + JDBCStatement s0 = new JDBCStatement(conn); + JDBCResultSet rs0 = null; + try { + rs0 = (JDBCResultSet) + (s0.executeQuery("PRAGMA index_list(" + + SQLite.Shell.sql_quote(table) + ")")); + } catch (SQLException e) { + throw e; + } finally { + s0.close(); + } + String cols[] = { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", + "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", + "ASC_OR_DESC", "CARDINALITY", "PAGES", + "FILTER_CONDITION" + }; + int types[] = { + Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, + Types.BIT, Types.VARCHAR, Types.VARCHAR, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, + Types.VARCHAR, Types.INTEGER, Types.INTEGER, + Types.VARCHAR + }; + TableResultX tr = new TableResultX(); + tr.columns(cols); + tr.sql_types(types); + JDBCResultSet rs = new JDBCResultSet(tr, null); + if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) { + Hashtable<String, Integer> h0 = new Hashtable<String, Integer>(); + for (int i = 0; i < rs0.tr.ncolumns; i++) { + h0.put(rs0.tr.column[i], new Integer(i)); + } + for (int i = 0; i < rs0.tr.nrows; i++) { + String r0[] = (String [])(rs0.tr.rows.elementAt(i)); + int col = ((Integer) h0.get("unique")).intValue(); + String uniq = r0[col]; + col = ((Integer) h0.get("name")).intValue(); + String iname = r0[col]; + if (unique && uniq.charAt(0) == '0') { + continue; + } + JDBCStatement s1 = new JDBCStatement(conn); + JDBCResultSet rs1 = null; + try { + rs1 = (JDBCResultSet) + (s1.executeQuery("PRAGMA index_info(" + + SQLite.Shell.sql_quote(iname) + ")")); + } catch (SQLException e) { + } finally { + s1.close(); + } + if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) { + continue; + } + Hashtable<String, Integer> h1 = + new Hashtable<String, Integer>(); + for (int k = 0; k < rs1.tr.ncolumns; k++) { + h1.put(rs1.tr.column[k], new Integer(k)); + } + for (int k = 0; k < rs1.tr.nrows; k++) { + String r1[] = (String [])(rs1.tr.rows.elementAt(k)); + String row[] = new String[cols.length]; + row[0] = ""; + row[1] = ""; + row[2] = table; + row[3] = (uniq.charAt(0) != '0' || + (iname.charAt(0) == '(' && + iname.indexOf(" autoindex ") > 0)) ? "0" : "1"; + row[4] = ""; + row[5] = iname; + row[6] = "" + tableIndexOther; + col = ((Integer) h1.get("seqno")).intValue(); +// BEGIN android-changed + row[7] = "" + (Integer.parseInt(r1[col]) + 1); +// END android-changed + col = ((Integer) h1.get("name")).intValue(); + row[8] = r1[col]; + row[9] = "A"; + row[10] = "0"; + row[11] = "0"; + row[12] = null; + tr.newrow(row); + } + } + } + return rs; + } + + public boolean supportsResultSetType(int type) throws SQLException { + return type == ResultSet.CONCUR_READ_ONLY; + } + + public boolean supportsResultSetConcurrency(int type, int concurrency) + throws SQLException { + return false; + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, + String typeNamePattern, int[] types) + throws SQLException { + return null; + } + + public Connection getConnection() throws SQLException { + return conn; + } + + static String mapTypeName(int type) { + switch (type) { + case Types.INTEGER: return "integer"; + case Types.SMALLINT: return "smallint"; + case Types.FLOAT: return "float"; + case Types.DOUBLE: return "double"; + case Types.TIMESTAMP: return "timestamp"; + case Types.DATE: return "date"; + case Types.TIME: return "time"; + case Types.BINARY: return "binary"; + case Types.VARBINARY: return "varbinary"; + } + return "varchar"; + } + + static int mapSqlType(String type) { + if (type == null) { + return Types.VARCHAR; + } + type = type.toLowerCase(); + if (type.startsWith("inter")) { + return Types.VARCHAR; + } + if (type.startsWith("numeric") || + type.startsWith("int")) { + return Types.INTEGER; + } + if (type.startsWith("tinyint") || + type.startsWith("smallint")) { + return Types.SMALLINT; + } + if (type.startsWith("float")) { + return Types.FLOAT; + } + if (type.startsWith("double")) { + return Types.DOUBLE; + } + if (type.startsWith("datetime") || + type.startsWith("timestamp")) { + return Types.TIMESTAMP; + } + if (type.startsWith("date")) { + return Types.DATE; + } + if (type.startsWith("time")) { + return Types.TIME; + } + if (type.startsWith("blob")) { + return Types.BINARY; + } + if (type.startsWith("binary")) { + return Types.BINARY; + } + if (type.startsWith("varbinary")) { + return Types.VARBINARY; + } + return Types.VARCHAR; + } + + static int getM(String typeStr, int type) { + int m = 65536; + switch (type) { + case Types.INTEGER: m = 11; break; + case Types.SMALLINT: m = 6; break; + case Types.FLOAT: m = 25; break; + case Types.DOUBLE: m = 54; break; + case Types.TIMESTAMP: return 30; + case Types.DATE: return 10; + case Types.TIME: return 8; + } + typeStr = typeStr.toLowerCase(); + int i1 = typeStr.indexOf('('); + if (i1 > 0) { + ++i1; + int i2 = typeStr.indexOf(',', i1); + if (i2 < 0) { + i2 = typeStr.indexOf(')', i1); + } + if (i2 - i1 > 0) { + String num = typeStr.substring(i1, i2); + try { + m = java.lang.Integer.parseInt(num, 10); + } catch (NumberFormatException e) { + } + } + } + return m; + } + + static int getD(String typeStr, int type) { + int d = 0; + switch (type) { + case Types.INTEGER: d = 10; break; + case Types.SMALLINT: d = 5; break; + case Types.FLOAT: d = 24; break; + case Types.DOUBLE: d = 53; break; + default: return getM(typeStr, type); + } + typeStr = typeStr.toLowerCase(); + int i1 = typeStr.indexOf('('); + if (i1 > 0) { + ++i1; + int i2 = typeStr.indexOf(',', i1); + if (i2 < 0) { + return getM(typeStr, type); + } + i1 = i2; + i2 = typeStr.indexOf(')', i1); + if (i2 - i1 > 0) { + String num = typeStr.substring(i1, i2); + try { + d = java.lang.Integer.parseInt(num, 10); + } catch (NumberFormatException e) { + } + } + } + return d; + } + + public boolean supportsSavepoints() { + return false; + } + + public boolean supportsNamedParameters() { + return false; + } + + public boolean supportsMultipleOpenResults() { + return false; + } + + public boolean supportsGetGeneratedKeys() { + return false; + } + + public boolean supportsResultSetHoldability(int x) { + return false; + } + + public boolean supportsStatementPooling() { + return false; + } + + public boolean locatorsUpdateCopy() throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, + String typeNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, + String tableNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, + String typeNamePattern, + String attributeNamePattern) + throws SQLException { + throw new SQLException("not supported"); + } + + public int getResultSetHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + + public int getDatabaseMajorVersion() { + return SQLite.JDBCDriver.MAJORVERSION; + } + + public int getDatabaseMinorVersion() { + return SQLite.JDBCDriver.MINORVERSION; + } + + public int getJDBCMajorVersion() { + return 1; + } + + public int getJDBCMinorVersion() { + return 0; + } + + public int getSQLStateType() throws SQLException { + return sqlStateXOpen; + } + +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java b/sql/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java new file mode 100644 index 0000000..ab81867 --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCPreparedStatement.java @@ -0,0 +1,752 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.math.BigDecimal; +import java.util.*; + +class BatchArg { + String arg; + boolean blob; + + BatchArg(String arg, boolean blob) { + if (arg == null) { + this.arg = null; + } else { + this.arg = new String(arg); + } + this.blob = blob; + } +} + +public class JDBCPreparedStatement extends JDBCStatement + implements java.sql.PreparedStatement { + + private String sql; + private String args[]; + private boolean blobs[]; + private ArrayList<BatchArg> batch; + private static final boolean nullrepl = + SQLite.Database.version().compareTo("2.5.0") < 0; + + public JDBCPreparedStatement(JDBCConnection conn, String sql) { + super(conn); + this.args = null; + this.blobs = null; + this.batch = null; + this.sql = fixup(sql); + } + + private String fixup(String sql) { + StringBuffer sb = new StringBuffer(); + boolean inq = false; + int nparm = 0; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '\'') { + if (inq) { + char nextChar = 0; + if(i + 1 < sql.length()) { + nextChar = sql.charAt(i + 1); + } + if (nextChar == '\'') { + sb.append(c); + sb.append(nextChar); + i++; + } else { + inq = false; + sb.append(c); + } + } else { + inq = true; + sb.append(c); + } + } else if (c == '?') { + if (inq) { + sb.append(c); + } else { + ++nparm; + sb.append(nullrepl ? "'%q'" : "%Q"); + } + } else if (c == ';') { + if (!inq) { + break; + } + sb.append(c); + } else if (c == '%') { + sb.append("%%"); + } else { + sb.append(c); + } + } + args = new String[nparm]; + blobs = new boolean[nparm]; + try { + clearParameters(); + } catch (SQLException e) { + } + return sb.toString(); + } + + private String fixup2(String sql) { + if (!conn.db.is3()) { + return sql; + } + StringBuffer sb = new StringBuffer(); + int parm = -1; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '%') { + sb.append(c); + ++i; + c = sql.charAt(i); + if (c == 'Q') { + parm++; + if (blobs[parm]) { + c = 's'; + } + } + } + sb.append(c); + } + return sb.toString(); + } + + public ResultSet executeQuery() throws SQLException { + return executeQuery(fixup2(sql), args, false); + } + + public int executeUpdate() throws SQLException { + executeQuery(fixup2(sql), args, true); + return updcnt; + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = nullrepl ? "" : null; + blobs[parameterIndex - 1] = false; + } + + public void setBoolean(int parameterIndex, boolean x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = x ? "1" : "0"; + blobs[parameterIndex - 1] = false; + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setShort(int parameterIndex, short x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setInt(int parameterIndex, int x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setLong(int parameterIndex, long x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + args[parameterIndex - 1] = "" + x; + blobs[parameterIndex - 1] = false; + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = "" + x; + } + blobs[parameterIndex - 1] = false; + } + + public void setString(int parameterIndex, String x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x; + } + blobs[parameterIndex - 1] = false; + } + + public void setBytes(int parameterIndex, byte x[]) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + blobs[parameterIndex - 1] = false; + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (conn.db.is3()) { + args[parameterIndex - 1] = SQLite.StringEncoder.encodeX(x); + blobs[parameterIndex - 1] = true; + } else { + args[parameterIndex - 1] = SQLite.StringEncoder.encode(x); + } + } + } + + public void setDate(int parameterIndex, java.sql.Date x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setTime(int parameterIndex, java.sql.Time x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setTimestamp(int parameterIndex, java.sql.Timestamp x) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + args[parameterIndex - 1] = x.toString(); + } + blobs[parameterIndex - 1] = false; + } + + public void setAsciiStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public void setUnicodeStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void setBinaryStream(int parameterIndex, java.io.InputStream x, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void clearParameters() throws SQLException { + for (int i = 0; i < args.length; i++) { + args[i] = nullrepl ? "" : null; + blobs[i] = false; + } + } + + public void setObject(int parameterIndex, Object x, int targetSqlType, + int scale) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public void setObject(int parameterIndex, Object x, int targetSqlType) + throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + if (parameterIndex < 1 || parameterIndex > args.length) { + throw new SQLException("bad parameter index"); + } + if (x == null) { + args[parameterIndex - 1] = nullrepl ? "" : null; + } else { + if (x instanceof byte[]) { + byte[] bx = (byte[]) x; + if (conn.db.is3()) { + args[parameterIndex - 1] = + SQLite.StringEncoder.encodeX(bx); + blobs[parameterIndex - 1] = true; + return; + } + args[parameterIndex - 1] = SQLite.StringEncoder.encode(bx); + } else { + args[parameterIndex - 1] = x.toString(); + } + } + blobs[parameterIndex - 1] = false; + } + + public boolean execute() throws SQLException { + return executeQuery(fixup2(sql), args, false) != null; + } + + public void addBatch() throws SQLException { + if (batch == null) { + batch = new ArrayList<BatchArg>(args.length); + } + for (int i = 0; i < args.length; i++) { + batch.add(new BatchArg(args[i], blobs[i])); + } + } + + public int[] executeBatch() throws SQLException { + if (batch == null) { + return new int[0]; + } + int[] ret = new int[batch.size() / args.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = EXECUTE_FAILED; + } + int errs = 0; + int index = 0; + for (int i = 0; i < ret.length; i++) { + for (int k = 0; k < args.length; k++) { + BatchArg b = (BatchArg) batch.get(index++); + + args[i] = b.arg; + blobs[i] = b.blob; + } + try { + ret[i] = executeUpdate(); + } catch (SQLException e) { + ++errs; + } + } + if (errs > 0) { + throw new BatchUpdateException("batch failed", ret); + } + return ret; + } + + public void clearBatch() throws SQLException { + if (batch != null) { + batch.clear(); + batch = null; + } + } + + public void setCharacterStream(int parameterIndex, + java.io.Reader reader, + int length) throws SQLException { + throw new SQLException("not supported"); + } + + public void setRef(int i, Ref x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setBlob(int i, Blob x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setClob(int i, Clob x) throws SQLException { + throw new SQLException("not supported"); + } + + public void setArray(int i, Array x) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSetMetaData getMetaData() throws SQLException { + return rs.getMetaData(); + } + + public void setDate(int parameterIndex, java.sql.Date x, Calendar cal) + throws SQLException { + setDate(parameterIndex, x); + } + + public void setTime(int parameterIndex, java.sql.Time x, Calendar cal) + throws SQLException { + setTime(parameterIndex, x); + } + + public void setTimestamp(int parameterIndex, java.sql.Timestamp x, + Calendar cal) throws SQLException { + setTimestamp(parameterIndex, x); + } + + public void setNull(int parameterIndex, int sqlType, String typeName) + throws SQLException { + setNull(parameterIndex, sqlType); + } + + public ParameterMetaData getParameterMetaData() throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType, + int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public void registerOutputParameter(String parameterName, int sqlType, + String typeName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.net.URL getURL(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void setURL(int parameterIndex, java.net.URL url) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setNull(String parameterName, int sqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBoolean(String parameterName, boolean val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setByte(String parameterName, byte val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setShort(String parameterName, short val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setInt(String parameterName, int val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setLong(String parameterName, long val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setFloat(String parameterName, float val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDouble(String parameterName, double val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBigDecimal(String parameterName, BigDecimal val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setString(String parameterName, String val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBytes(String parameterName, byte val[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDate(String parameterName, java.sql.Date val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTime(String parameterName, java.sql.Time val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTimestamp(String parameterName, java.sql.Timestamp val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setAsciiStream(String parameterName, + java.io.InputStream s, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setBinaryStream(String parameterName, + java.io.InputStream s, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val, int targetSqlType, + int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val, int targetSqlType) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setObject(String parameterName, Object val) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setCharacterStream(String parameterName, + java.io.Reader r, int length) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setDate(String parameterName, java.sql.Date val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTime(String parameterName, java.sql.Time val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setTimestamp(String parameterName, java.sql.Timestamp val, + Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public void setNull(String parameterName, int sqlType, String typeName) + throws SQLException { + throw new SQLException("not supported"); + } + + public String getString(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getBoolean(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public short getShort(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public int getInt(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public long getLong(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public float getFloat(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public double getDouble(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte[] getBytes(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(String parameterName) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String parameterName, Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(int parameterIndex, Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Ref getRef(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Ref getRef(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Blob getBlob(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Blob getBlob(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Clob getClob(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Clob getClob(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public Array getArray(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + + public Array getArray(int parameterIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Date getDate(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Time getTime(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(String parameterName, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Timestamp getTimestamp(int parameterIndex, Calendar cal) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.net.URL getURL(String parameterName) throws SQLException { + throw new SQLException("not supported"); + } + +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCResultSet.java b/sql/src/main/java/SQLite/JDBC2y/JDBCResultSet.java new file mode 100644 index 0000000..06384eb --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCResultSet.java @@ -0,0 +1,932 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.math.BigDecimal; + +public class JDBCResultSet implements java.sql.ResultSet { + + /** + * Current row to be retrieved. + */ + private int row; + + /** + * Table returned by Database.get_table() + */ + protected SQLite.TableResult tr; + + /** + * Statement from which result set was produced. + */ + private JDBCStatement s; + + /** + * Meta data for result set or null. + */ + private JDBCResultSetMetaData m; + + /** + * Last result cell retrieved or null. + */ + private String lastg; + + + public JDBCResultSet(SQLite.TableResult tr, JDBCStatement s) { + this.tr = tr; + this.s = s; + this.m = null; + this.lastg = null; + this.row = -1; + } + + public boolean next() throws SQLException { + if (tr == null) { + return false; + } + row++; + return row < tr.nrows; + } + + public int findColumn(String columnName) throws SQLException { + JDBCResultSetMetaData m = (JDBCResultSetMetaData) getMetaData(); + return m.findColByName(columnName); + } + + public int getRow() throws SQLException { + if (tr == null) { + throw new SQLException("no rows"); + } + return row + 1; + } + + public boolean previous() throws SQLException { + if (tr == null) { + return false; + } + if (row >= 0) { + row--; + } + return row >= 0; + } + + public boolean absolute(int row) throws SQLException { + if (tr == null) { + return false; + } + if (row < 0) { + row = tr.nrows + 1 + row; + } + row--; + if (row < 0 || row > tr.nrows) { + return false; + } + this.row = row; + return true; + } + + public boolean relative(int row) throws SQLException { + if (tr == null) { + return false; + } + if (this.row + row < 0 || this.row + row >= tr.nrows) { + return false; + } + this.row += row; + return true; + } + + public void setFetchDirection(int dir) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchDirection() throws SQLException { + throw new SQLException("not supported"); + } + + public void setFetchSize(int fsize) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchSize() throws SQLException { + throw new SQLException("not supported"); + } + + public String getString(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + return lastg; + } + + public String getString(String columnName) throws SQLException { + int col = findColumn(columnName); + return getString(col); + } + + public int getInt(int columnIndex) throws SQLException { + Integer i = internalGetInt(columnIndex); + if (i != null) { + return i.intValue(); + } + return 0; + } + + private Integer internalGetInt(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Integer.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public int getInt(String columnName) throws SQLException { + int col = findColumn(columnName); + return getInt(col); + } + + public boolean getBoolean(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getBoolean(String columnName) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSetMetaData getMetaData() throws SQLException { + if (m == null) { + m = new JDBCResultSetMetaData(this); + } + return m; + } + + public short getShort(int columnIndex) throws SQLException { + Short s = internalGetShort(columnIndex); + if (s != null) { + return s.shortValue(); + } + return 0; + } + + private Short internalGetShort(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Short.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public short getShort(String columnName) throws SQLException { + int col = findColumn(columnName); + return getShort(col); + } + + public java.sql.Time getTime(int columnIndex) throws SQLException { + return internalGetTime(columnIndex, null); + } + + private java.sql.Time internalGetTime(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Time.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Time getTime(String columnName) throws SQLException { + int col = findColumn(columnName); + return getTime(col); + } + + public java.sql.Time getTime(int columnIndex, java.util.Calendar cal) + throws SQLException { + return internalGetTime(columnIndex, cal); + } + + public java.sql.Time getTime(String columnName, java.util.Calendar cal) + throws SQLException{ + int col = findColumn(columnName); + return getTime(col, cal); + } + + public java.sql.Timestamp getTimestamp(int columnIndex) + throws SQLException{ + return internalGetTimestamp(columnIndex, null); + } + + private java.sql.Timestamp internalGetTimestamp(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Timestamp.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Timestamp getTimestamp(String columnName) + throws SQLException{ + int col = findColumn(columnName); + return getTimestamp(col); + } + + public java.sql.Timestamp getTimestamp(int columnIndex, + java.util.Calendar cal) + throws SQLException { + return internalGetTimestamp(columnIndex, cal); + } + + public java.sql.Timestamp getTimestamp(String columnName, + java.util.Calendar cal) + throws SQLException { + int col = findColumn(columnName); + return getTimestamp(col, cal); + } + + public java.sql.Date getDate(int columnIndex) throws SQLException { + return internalGetDate(columnIndex, null); + } + + private java.sql.Date internalGetDate(int columnIndex, + java.util.Calendar cal) + throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return java.sql.Date.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public java.sql.Date getDate(String columnName) throws SQLException { + int col = findColumn(columnName); + return getDate(col); + } + + public java.sql.Date getDate(int columnIndex, java.util.Calendar cal) + throws SQLException{ + return internalGetDate(columnIndex, cal); + } + + public java.sql.Date getDate(String columnName, java.util.Calendar cal) + throws SQLException{ + int col = findColumn(columnName); + return getDate(col, cal); + } + + public double getDouble(int columnIndex) throws SQLException { + Double d = internalGetDouble(columnIndex); + if (d != null) { + return d.doubleValue(); + } + return 0; + } + + private Double internalGetDouble(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Double.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public double getDouble(String columnName) throws SQLException { + int col = findColumn(columnName); + return getDouble(col); + } + + public float getFloat(int columnIndex) throws SQLException { + Float f = internalGetFloat(columnIndex); + if (f != null) { + return f.floatValue(); + } + return 0; + } + + private Float internalGetFloat(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Float.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public float getFloat(String columnName) throws SQLException { + int col = findColumn(columnName); + return getFloat(col); + } + + public long getLong(int columnIndex) throws SQLException { + Long l = internalGetLong(columnIndex); + if (l != null) { + return l.longValue(); + } + return 0; + } + + private Long internalGetLong(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + try { + return Long.valueOf(lastg); + } catch (java.lang.Exception e) { + lastg = null; + } + return null; + } + + public long getLong(String columnName) throws SQLException { + int col = findColumn(columnName); + return getLong(col); + } + + @Deprecated + public java.io.InputStream getUnicodeStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public java.io.InputStream getUnicodeStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getAsciiStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getAsciiStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public BigDecimal getBigDecimal(String columnName, int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + @Deprecated + public BigDecimal getBigDecimal(int columnIndex, int scale) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getBinaryStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.InputStream getBinaryStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public byte getByte(String columnName) throws SQLException { + throw new SQLException("not supported"); + } + + public byte[] getBytes(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + byte ret[] = null; + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + if (lastg != null) { + ret = SQLite.StringEncoder.decode(lastg); + } + return ret; + } + + public byte[] getBytes(String columnName) throws SQLException { + int col = findColumn(columnName); + return getBytes(col); + } + + public String getCursorName() throws SQLException { + return null; + } + + public Object getObject(int columnIndex) throws SQLException { + if (tr == null || columnIndex < 1 || columnIndex > tr.ncolumns) { + throw new SQLException("column " + columnIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[columnIndex - 1]; + Object ret = lastg; + if (tr instanceof TableResultX) { + switch (((TableResultX) tr).sql_type[columnIndex - 1]) { + case Types.SMALLINT: + ret = internalGetShort(columnIndex); + break; + case Types.INTEGER: + ret = internalGetInt(columnIndex); + break; + case Types.DOUBLE: + ret = internalGetDouble(columnIndex); + break; + case Types.FLOAT: + ret = internalGetFloat(columnIndex); + break; + case Types.BIGINT: + ret = internalGetLong(columnIndex); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + ret = getBytes(columnIndex); + break; + case Types.NULL: + ret = null; + break; + /* defaults to String below */ + } + } + return ret; + } + + public Object getObject(String columnName) throws SQLException { + int col = findColumn(columnName); + return getObject(col); + } + + public Object getObject(int columnIndex, java.util.Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public Object getObject(String columnIndex, java.util.Map map) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Ref getRef(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Ref getRef(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Blob getBlob(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Blob getBlob(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Clob getClob(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Clob getClob(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Array getArray(int columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.sql.Array getArray(String columnIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.Reader getCharacterStream(int columnIndex) + throws SQLException { + throw new SQLException("not supported"); + } + + public java.io.Reader getCharacterStream(String columnName) + throws SQLException { + throw new SQLException("not supported"); + } + + public SQLWarning getWarnings() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean wasNull() throws SQLException { + return lastg == null; + } + + public void clearWarnings() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean isFirst() throws SQLException { + if (tr == null) { + return true; + } + return row == 0; + } + + public boolean isBeforeFirst() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + return row < 0; + } + + public void beforeFirst() throws SQLException { + if (tr == null) { + return; + } + row = -1; + } + + public boolean first() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + row = 0; + return true; + } + + public boolean isAfterLast() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + return row >= tr.nrows; + } + + public void afterLast() throws SQLException { + if (tr == null) { + return; + } + row = tr.nrows; + } + + public boolean isLast() throws SQLException { + if (tr == null) { + return true; + } + return row == tr.nrows - 1; + } + + public boolean last() throws SQLException { + if (tr == null || tr.nrows <= 0) { + return false; + } + row = tr.nrows -1; + return true; + } + + public int getType() throws SQLException { + return TYPE_SCROLL_INSENSITIVE; + } + + public int getConcurrency() throws SQLException { + return CONCUR_READ_ONLY; + } + + public boolean rowUpdated() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean rowInserted() throws SQLException { + throw new SQLException("not supported"); + } + + public boolean rowDeleted() throws SQLException { + throw new SQLException("not supported"); + } + + public void insertRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void updateRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void deleteRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void refreshRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void cancelRowUpdates() throws SQLException { + throw new SQLException("not supported"); + } + + public void moveToInsertRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void moveToCurrentRow() throws SQLException { + throw new SQLException("not supported"); + } + + public void updateNull(int colIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBoolean(int colIndex, boolean b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateByte(int colIndex, byte b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateShort(int colIndex, short b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateInt(int colIndex, int b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateLong(int colIndex, long b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateFloat(int colIndex, float f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDouble(int colIndex, double f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBigDecimal(int colIndex, BigDecimal f) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateString(int colIndex, String s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBytes(int colIndex, byte[] s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDate(int colIndex, java.sql.Date d) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTime(int colIndex, java.sql.Time t) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTimestamp(int colIndex, java.sql.Timestamp t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateAsciiStream(int colIndex, java.io.InputStream in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBinaryStream(int colIndex, java.io.InputStream in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateCharacterStream(int colIndex, java.io.Reader in, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(int colIndex, Object obj) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(int colIndex, Object obj, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateNull(String colIndex) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBoolean(String colIndex, boolean b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateByte(String colIndex, byte b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateShort(String colIndex, short b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateInt(String colIndex, int b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateLong(String colIndex, long b) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateFloat(String colIndex, float f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDouble(String colIndex, double f) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBigDecimal(String colIndex, BigDecimal f) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateString(String colIndex, String s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBytes(String colIndex, byte[] s) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateDate(String colIndex, java.sql.Date d) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTime(String colIndex, java.sql.Time t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateTimestamp(String colIndex, java.sql.Timestamp t) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateAsciiStream(String colIndex, java.io.InputStream in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBinaryStream(String colIndex, java.io.InputStream in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateCharacterStream(String colIndex, java.io.Reader in, + int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(String colIndex, Object obj) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateObject(String colIndex, Object obj, int s) + throws SQLException { + throw new SQLException("not supported"); + } + + public Statement getStatement() throws SQLException { + if (s == null) { + throw new SQLException("stale result set"); + } + return s; + } + + public void close() throws SQLException { + s = null; + tr = null; + lastg = null; + row = -1; + } + + public java.net.URL getURL(int colIndex) throws SQLException { + if (tr == null || colIndex < 1 || colIndex > tr.ncolumns) { + throw new SQLException("column " + colIndex + " not found"); + } + String rd[] = (String []) tr.rows.elementAt(row); + lastg = rd[colIndex - 1]; + java.net.URL url = null; + if (lastg == null) { + return url; + } + try { + url = new java.net.URL(lastg); + } catch (java.lang.Exception e) { + url = null; + } + return url; + } + + public java.net.URL getURL(String colIndex) throws SQLException { + int col = findColumn(colIndex); + return getURL(col); + } + + public void updateRef(int colIndex, java.sql.Ref x) throws SQLException { + throw new SQLException("not supported"); + } + + public void updateRef(String colIndex, java.sql.Ref x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBlob(int colIndex, java.sql.Blob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateBlob(String colIndex, java.sql.Blob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateClob(int colIndex, java.sql.Clob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateClob(String colIndex, java.sql.Clob x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateArray(int colIndex, java.sql.Array x) + throws SQLException { + throw new SQLException("not supported"); + } + + public void updateArray(String colIndex, java.sql.Array x) + throws SQLException { + throw new SQLException("not supported"); + } + +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java b/sql/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java new file mode 100644 index 0000000..934ca78 --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCResultSetMetaData.java @@ -0,0 +1,212 @@ +package SQLite.JDBC2y; + +import java.sql.*; + +public class JDBCResultSetMetaData implements java.sql.ResultSetMetaData { + + private JDBCResultSet r; + + public JDBCResultSetMetaData(JDBCResultSet r) { + this.r = r; + } + + public String getCatalogName(int column) throws java.sql.SQLException { + return null; + } + + public String getColumnClassName(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return null; + } + if (r.tr instanceof TableResultX) { + switch (((TableResultX) r.tr).sql_type[column]) { + case Types.SMALLINT: return "java.lang.Short"; + case Types.INTEGER: return "java.lang.Integer"; + case Types.DOUBLE: return "java.lang.Double"; + case Types.FLOAT: return "java.lang.Float"; + case Types.BIGINT: return "java.lang.Long"; + case Types.DATE: return "java.sql.Date"; + case Types.TIME: return "java.sql.Time"; + case Types.TIMESTAMP: return "java.sql.Timestamp"; + case Types.BINARY: + case Types.VARBINARY: return "[B"; + /* defaults to varchar below */ + } + } + return "java.lang.String"; + } + return null; + } + + public int getColumnCount() throws java.sql.SQLException { + if (r != null && r.tr != null) { + return r.tr.ncolumns; + } + return 0; + } + + public int getColumnDisplaySize(int column) throws java.sql.SQLException { + return 0; + } + + public String getColumnLabel(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + } + return c; + } + + public String getColumnName(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + if (c != null) { + int i = c.indexOf('.'); + if (i > 0) { + return c.substring(i + 1); + } + } + } + return c; + } + + public int getColumnType(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column >= 0 && column < r.tr.ncolumns) { + if (r.tr instanceof TableResultX) { + return ((TableResultX) r.tr).sql_type[column]; + } + return Types.VARCHAR; + } + } + throw new SQLException("bad column index"); + } + + public String getColumnTypeName(int column) throws java.sql.SQLException { + column--; + if (r != null && r.tr != null) { + if (column >= 0 && column < r.tr.ncolumns) { + if (r.tr instanceof TableResultX) { + switch (((TableResultX) r.tr).sql_type[column]) { + case Types.SMALLINT: return "smallint"; + case Types.INTEGER: return "integer"; + case Types.DOUBLE: return "double"; + case Types.FLOAT: return "float"; + case Types.BIGINT: return "bigint"; + case Types.DATE: return "date"; + case Types.TIME: return "time"; + case Types.TIMESTAMP: return "timestamp"; + case Types.BINARY: return "binary"; + case Types.VARBINARY: return "varbinary"; + /* defaults to varchar below */ + } + } + return "varchar"; + } + } + throw new SQLException("bad column index"); + } + + public int getPrecision(int column) throws java.sql.SQLException { + return 0; + } + + public int getScale(int column) throws java.sql.SQLException { + return 0; + } + + public String getSchemaName(int column) throws java.sql.SQLException { + return null; + } + + public String getTableName(int column) throws java.sql.SQLException { + column--; + String c = null; + if (r != null && r.tr != null) { + if (column < 0 || column >= r.tr.ncolumns) { + return c; + } + c = r.tr.column[column]; + if (c != null) { + int i = c.indexOf('.'); + if (i > 0) { + return c.substring(0, i); + } + c = null; + } + } + return c; + } + + public boolean isAutoIncrement(int column) throws java.sql.SQLException { + return false; + } + + public boolean isCaseSensitive(int column) throws java.sql.SQLException { + return false; + } + + public boolean isCurrency(int column) throws java.sql.SQLException { + return false; + } + + public boolean isDefinitelyWritable(int column) + throws java.sql.SQLException { + return true; + } + + public int isNullable(int column) throws java.sql.SQLException { + return columnNullableUnknown; + } + + public boolean isReadOnly(int column) throws java.sql.SQLException { + return false; + } + + public boolean isSearchable(int column) throws java.sql.SQLException { + return true; + } + + public boolean isSigned(int column) throws java.sql.SQLException { + return false; + } + + public boolean isWritable(int column) throws java.sql.SQLException { + return true; + } + + int findColByName(String columnName) throws java.sql.SQLException { + String c = null; + if (r != null && r.tr != null) { + for (int i = 0; i < r.tr.ncolumns; i++) { + c = r.tr.column[i]; + if (c != null) { + if (c.compareToIgnoreCase(columnName) == 0) { + return i + 1; + } + int k = c.indexOf('.'); + if (k > 0) { + c = c.substring(k + 1); + if (c.compareToIgnoreCase(columnName) == 0) { + return i + 1; + } + } + } + c = null; + } + } + throw new SQLException("column " + columnName + " not found"); + } +} diff --git a/sql/src/main/java/SQLite/JDBC2y/JDBCStatement.java b/sql/src/main/java/SQLite/JDBC2y/JDBCStatement.java new file mode 100644 index 0000000..99d12d3 --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/JDBCStatement.java @@ -0,0 +1,287 @@ +package SQLite.JDBC2y; + +import java.sql.*; +import java.util.*; + +public class JDBCStatement implements java.sql.Statement { + + protected JDBCConnection conn; + protected JDBCResultSet rs; + protected int updcnt; + private ArrayList<String> batch; + + public JDBCStatement(JDBCConnection conn) { + this.conn = conn; + this.updcnt = 0; + this.rs = null; + this.batch = null; + } + + public void setFetchSize(int fetchSize) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchSize() throws SQLException { + return 1; + } + + public int getMaxRows() throws SQLException { + return 0; + } + + public void setMaxRows(int max) throws SQLException { + throw new SQLException("not supported"); + } + + public void setFetchDirection(int fetchDirection) throws SQLException { + throw new SQLException("not supported"); + } + + public int getFetchDirection() throws SQLException { + return ResultSet.FETCH_UNKNOWN; + } + + public int getResultSetConcurrency() throws SQLException { + return ResultSet.CONCUR_READ_ONLY; + } + + public int getResultSetType() throws SQLException { + return ResultSet.TYPE_SCROLL_INSENSITIVE; + } + + public void setQueryTimeout(int seconds) throws SQLException { + conn.timeout = seconds * 1000; + if (conn.timeout < 0) { + conn.timeout = 120000; + } else if (conn.timeout < 1000) { + conn.timeout = 5000; + } + } + + public int getQueryTimeout() throws SQLException { + return conn.timeout; + } + + public ResultSet getResultSet() throws SQLException { + return rs; + } + + ResultSet executeQuery(String sql, String args[], boolean updonly) + throws SQLException { + SQLite.TableResult tr = null; + if (rs != null) { + rs.close(); + rs = null; + } + updcnt = -1; + if (conn == null || conn.db == null) { + throw new SQLException("stale connection"); + } + int busy = 0; + boolean starttrans = !conn.autocommit && !conn.intrans; + while (true) { + try { + if (starttrans) { + conn.db.exec("BEGIN TRANSACTION", null); + conn.intrans = true; + } + if (args == null) { + if (updonly) { + conn.db.exec(sql, null); + } else { + tr = conn.db.get_table(sql); + } + } else { + if (updonly) { + conn.db.exec(sql, null, args); + } else { + tr = conn.db.get_table(sql, args); + } + } + updcnt = (int) conn.db.changes(); + } catch (SQLite.Exception e) { + if (conn.db.is3() && + conn.db.last_error() == SQLite.Constants.SQLITE_BUSY && + conn.busy3(conn.db, ++busy)) { + try { + if (starttrans && conn.intrans) { + conn.db.exec("ROLLBACK", null); + conn.intrans = false; + } + } catch (SQLite.Exception ee) { + } + try { + int ms = 20 + busy * 10; + if (ms > 1000) { + ms = 1000; + } + synchronized (this) { + this.wait(ms); + } + } catch (java.lang.Exception eee) { + } + continue; + } + throw new SQLException(e.toString()); + } + break; + } + if (!updonly && tr == null) { + throw new SQLException("no result set produced"); + } + if (!updonly && tr != null) { + rs = new JDBCResultSet(new TableResultX(tr), this); + } + return rs; + } + + public ResultSet executeQuery(String sql) throws SQLException { + return executeQuery(sql, null, false); + } + + public boolean execute(String sql) throws SQLException { + return executeQuery(sql) != null; + } + + public void cancel() throws SQLException { + if (conn == null || conn.db == null) { + throw new SQLException("stale connection"); + } + conn.db.interrupt(); + } + + public void clearWarnings() throws SQLException { + } + + public Connection getConnection() throws SQLException { + return conn; + } + + public void addBatch(String sql) throws SQLException { + if (batch == null) { + batch = new ArrayList<String>(1); + } + batch.add(sql); + } + + public int[] executeBatch() throws SQLException { + if (batch == null) { + return new int[0]; + } + int[] ret = new int[batch.size()]; + for (int i = 0; i < ret.length; i++) { + ret[i] = EXECUTE_FAILED; + } + int errs = 0; + for (int i = 0; i < ret.length; i++) { + try { + execute((String) batch.get(i)); + ret[i] = updcnt; + } catch (SQLException e) { + ++errs; + } + } + if (errs > 0) { + throw new BatchUpdateException("batch failed", ret); + } + return ret; + } + + public void clearBatch() throws SQLException { + if (batch != null) { + batch.clear(); + batch = null; + } + } + + public void close() throws SQLException { + clearBatch(); + conn = null; + } + + public int executeUpdate(String sql) throws SQLException { + executeQuery(sql, null, true); + return updcnt; + } + + public int getMaxFieldSize() throws SQLException { + return 0; + } + + public boolean getMoreResults() throws SQLException { + if (rs != null) { + rs.close(); + rs = null; + } + return false; + } + + public int getUpdateCount() throws SQLException { + return updcnt; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public void setCursorName(String name) throws SQLException { + throw new SQLException("not supported"); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + throw new SQLException("not supported"); + } + + public void setMaxFieldSize(int max) throws SQLException { + throw new SQLException("not supported"); + } + + public boolean getMoreResults(int x) throws SQLException { + throw new SQLException("not supported"); + } + + public ResultSet getGeneratedKeys() throws SQLException { + throw new SQLException("not supported"); + } + + public int executeUpdate(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return executeUpdate(sql); + } + + public int executeUpdate(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public int executeUpdate(String sql, String colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public boolean execute(String sql, int autokeys) + throws SQLException { + if (autokeys != Statement.NO_GENERATED_KEYS) { + throw new SQLException("not supported"); + } + return execute(sql); + } + + public boolean execute(String sql, int colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public boolean execute(String sql, String colIndexes[]) + throws SQLException { + throw new SQLException("not supported"); + } + + public int getResultSetHoldability() throws SQLException { + return ResultSet.HOLD_CURSORS_OVER_COMMIT; + } + +} diff --git a/sql/src/main/java/SQLite/JDBC2y/TableResultX.java b/sql/src/main/java/SQLite/JDBC2y/TableResultX.java new file mode 100644 index 0000000..205372f --- /dev/null +++ b/sql/src/main/java/SQLite/JDBC2y/TableResultX.java @@ -0,0 +1,37 @@ +package SQLite.JDBC2y; + +import java.sql.Types; +import java.util.Vector; + +public class TableResultX extends SQLite.TableResult { + public int sql_type[]; + + public TableResultX() { + super(); + sql_type = new int[this.ncolumns]; + for (int i = 0; i < this.ncolumns; i++) { + sql_type[i] = Types.VARCHAR; + } + } + + public TableResultX(SQLite.TableResult tr) { + this.column = tr.column; + this.rows = tr.rows; + this.ncolumns = tr.ncolumns; + this.nrows = tr.nrows; + this.types = tr.types; + sql_type = new int[tr.ncolumns]; + for (int i = 0; i < this.ncolumns; i++) { + sql_type[i] = Types.VARCHAR; + } + if (tr.types != null) { + for (int i = 0; i < tr.types.length; i++) { + sql_type[i] = JDBCDatabaseMetaData.mapSqlType(tr.types[i]); + } + } + } + + void sql_types(int types[]) { + sql_type = types; + } +} diff --git a/sql/src/main/java/SQLite/JDBCDriver.java b/sql/src/main/java/SQLite/JDBCDriver.java new file mode 100644 index 0000000..63b95ee --- /dev/null +++ b/sql/src/main/java/SQLite/JDBCDriver.java @@ -0,0 +1,109 @@ +package SQLite; + +import java.sql.*; +import java.util.Properties; + +public class JDBCDriver implements java.sql.Driver { + + public static final int MAJORVERSION = 1; + public static final int MINORVERSION = 2; + + private static java.lang.reflect.Constructor makeConn = null; + + protected Connection conn; + + static { + try { + Class connClass = null; + Class args[] = new Class[2]; + args[0] = Class.forName("java.lang.String"); + args[1] = args[0]; + String jvers = java.lang.System.getProperty("java.version"); + String cvers; + if (jvers == null || jvers.startsWith("1.0")) { + throw new java.lang.Exception("unsupported java version"); + } else if (jvers.startsWith("1.1")) { + cvers = "SQLite.JDBC1.JDBCConnection"; + } else if (jvers.startsWith("1.2") || jvers.startsWith("1.3")) { + cvers = "SQLite.JDBC2.JDBCConnection"; + } else if (jvers.startsWith("1.4")) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } else if (jvers.startsWith("1.5")) { + cvers = "SQLite.JDBC2y.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception e) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } + } else { + cvers = "SQLite.JDBC2z.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception e) { + cvers = "SQLite.JDBC2y.JDBCConnection"; + try { + Class.forName(cvers); + } catch (java.lang.Exception ee) { + cvers = "SQLite.JDBC2x.JDBCConnection"; + } + } + } + connClass = Class.forName(cvers); + makeConn = connClass.getConstructor(args); + java.sql.DriverManager.registerDriver(new JDBCDriver()); + } catch (java.lang.Exception e) { + System.err.println(e); + } + } + + public JDBCDriver() { + } + + public boolean acceptsURL(String url) throws SQLException { + return url.startsWith("sqlite:/") || + url.startsWith("jdbc:sqlite:/"); + } + + public Connection connect(String url, Properties info) + throws SQLException { + if (!acceptsURL(url)) { + return null; + } + Object args[] = new Object[2]; + args[0] = url; + if (info != null) { + args[1] = info.getProperty("encoding"); + } + if (args[1] == null) { + args[1] = java.lang.System.getProperty("SQLite.encoding"); + } + try { + conn = (Connection) makeConn.newInstance(args); + } catch (java.lang.reflect.InvocationTargetException ie) { + throw new SQLException(ie.getTargetException().toString()); + } catch (java.lang.Exception e) { + throw new SQLException(e.toString()); + } + return conn; + } + + public int getMajorVersion() { + return MAJORVERSION; + } + + public int getMinorVersion() { + return MINORVERSION; + } + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) + throws SQLException { + DriverPropertyInfo p[] = new DriverPropertyInfo[1]; + DriverPropertyInfo pp = new DriverPropertyInfo("encoding", ""); + p[0] = pp; + return p; + } + + public boolean jdbcCompliant() { + return false; + } +} diff --git a/sql/src/main/java/SQLite/ProgressHandler.java b/sql/src/main/java/SQLite/ProgressHandler.java new file mode 100644 index 0000000..b2ec7c0 --- /dev/null +++ b/sql/src/main/java/SQLite/ProgressHandler.java @@ -0,0 +1,17 @@ +package SQLite; + +/** + * Callback interface for SQLite's user defined progress handler. + */ + +public interface ProgressHandler { + + /** + * Invoked for N SQLite VM opcodes. + * The method should return true to continue the + * current query, or false in order + * to abandon the action.<BR><BR> + */ + + public boolean progress(); +} diff --git a/sql/src/main/java/SQLite/Shell.java b/sql/src/main/java/SQLite/Shell.java new file mode 100644 index 0000000..78d37a1 --- /dev/null +++ b/sql/src/main/java/SQLite/Shell.java @@ -0,0 +1,669 @@ +package SQLite; + +import SQLite.*; +import java.io.*; +import java.util.*; + +/** + * SQLite command line shell. This is a partial reimplementaion + * of sqlite/src/shell.c and can be invoked by:<P> + * + * <verb> + * java SQLite.Shell [OPTIONS] database [SHELLCMD] + * or + * java -jar sqlite.jar [OPTIONS] database [SHELLCMD] + * </verb> + */ + +public class Shell implements Callback { + Database db; + boolean echo; + int count; + int mode; + boolean showHeader; + String tableName; + String sep; + String cols[]; + int colwidth[]; + String destTable; + PrintWriter pw; + PrintWriter err; + + static final int MODE_Line = 0; + static final int MODE_Column = 1; + static final int MODE_List = 2; + static final int MODE_Semi = 3; + static final int MODE_Html = 4; + static final int MODE_Insert = 5; + static final int MODE_Insert2 = 6; + + public Shell(PrintWriter pw, PrintWriter err) { + this.pw = pw; + this.err = err; + } + + public Shell(PrintStream ps, PrintStream errs) { + pw = new PrintWriter(ps); + err = new PrintWriter(errs); + } + + protected Object clone() { + Shell s = new Shell(this.pw, this.err); + s.db = db; + s.echo = echo; + s.mode = mode; + s.count = 0; + s.showHeader = showHeader; + s.tableName = tableName; + s.sep = sep; + s.colwidth = colwidth; + return s; + } + + static public String sql_quote_dbl(String str) { + if (str == null) { + return "NULL"; + } + int i, single = 0, dbl = 0; + for (i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\'') { + single++; + } else if (str.charAt(i) == '"') { + dbl++; + } + } + if (dbl == 0) { + return "\"" + str + "\""; + } + StringBuffer sb = new StringBuffer("\""); + for (i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '"') { + sb.append("\"\""); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + static public String sql_quote(String str) { + if (str == null) { + return "NULL"; + } + int i, single = 0, dbl = 0; + for (i = 0; i < str.length(); i++) { + if (str.charAt(i) == '\'') { + single++; + } else if (str.charAt(i) == '"') { + dbl++; + } + } + if (single == 0) { + return "'" + str + "'"; + } + if (dbl == 0) { + return "\"" + str + "\""; + } + StringBuffer sb = new StringBuffer("'"); + for (i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '\'') { + sb.append("''"); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + static String html_quote(String str) { + if (str == null) { + return "NULL"; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '&') { + sb.append("&"); + } else { + int x = c; + if (x < 32 || x > 127) { + sb.append("&#" + x + ";"); + } else { + sb.append(c); + } + } + } + return sb.toString(); + } + + static boolean is_numeric(String str) { + try { + Double d = Double.valueOf(str); + } catch (java.lang.Exception e) { + return false; + } + return true; + } + + void set_table_name(String str) { + if (str == null) { + tableName = ""; + return; + } + tableName = Shell.sql_quote(str); + } + + public void columns(String args[]) { + cols = args; + } + + public void types(String args[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public boolean newrow(String args[]) { + int i; + String tname; + switch (mode) { + case Shell.MODE_Line: + if (args.length == 0) { + break; + } + if (count++ > 0) { + pw.println(""); + } + for (i = 0; i < args.length; i++) { + pw.println(cols[i] + " = " + + args[i] == null ? "NULL" : args[i]); + } + break; + case Shell.MODE_Column: + String csep = ""; + if (count++ == 0) { + colwidth = new int[args.length]; + for (i = 0; i < args.length; i++) { + int w, n; + w = cols[i].length(); + if (w < 10) { + w = 10; + } + colwidth[i] = w; + if (showHeader) { + pw.print(csep + cols[i]); + csep = " "; + } + } + if (showHeader) { + pw.println(""); + } + } + if (args.length == 0) { + break; + } + csep = ""; + for (i = 0; i < args.length; i++) { + pw.print(csep + (args[i] == null ? "NULL" : args[i])); + csep = " "; + } + pw.println(""); + break; + case Shell.MODE_Semi: + case Shell.MODE_List: + if (count++ == 0 && showHeader) { + for (i = 0; i < args.length; i++) { + pw.print(cols[i] + + (i == args.length - 1 ? "\n" : sep)); + } + } + if (args.length == 0) { + break; + } + for (i = 0; i < args.length; i++) { + pw.print(args[i] == null ? "NULL" : args[i]); + if (mode == Shell.MODE_Semi) { + pw.print(";"); + } else if (i < args.length - 1) { + pw.print(sep); + } + } + pw.println(""); + break; + case MODE_Html: + if (count++ == 0 && showHeader) { + pw.print("<TR>"); + for (i = 0; i < args.length; i++) { + pw.print("<TH>" + html_quote(cols[i]) + "</TH>"); + } + pw.println("</TR>"); + } + if (args.length == 0) { + break; + } + pw.print("<TR>"); + for (i = 0; i < args.length; i++) { + pw.print("<TD>" + html_quote(args[i]) + "</TD>"); + } + pw.println("</TR>"); + break; + case MODE_Insert: + if (args.length == 0) { + break; + } + tname = tableName; + if (destTable != null) { + tname = destTable; + } + pw.print("INSERT INTO " + tname + " VALUES("); + for (i = 0; i < args.length; i++) { + String tsep = i > 0 ? "," : ""; + if (args[i] == null) { + pw.print(tsep + "NULL"); + } else if (is_numeric(args[i])) { + pw.print(tsep + args[i]); + } else { + pw.print(tsep + sql_quote(args[i])); + } + } + pw.println(");"); + break; + case MODE_Insert2: + if (args.length == 0) { + break; + } + tname = tableName; + if (destTable != null) { + tname = destTable; + } + pw.print("INSERT INTO " + tname + " VALUES("); + for (i = 0; i < args.length; i++) { + String tsep = i > 0 ? "," : ""; + pw.print(tsep + args[i]); + } + pw.println(");"); + break; + } + return false; + } + + void do_meta(String line) { + StringTokenizer st = new StringTokenizer(line.toLowerCase()); + int n = st.countTokens(); + if (n <= 0) { + return; + } + String cmd = st.nextToken(); + String args[] = new String[n - 1]; + int i = 0; + while (st.hasMoreTokens()) { + args[i] = st.nextToken(); + ++i; + } + if (cmd.compareTo(".dump") == 0) { + new DBDump(this, args); + return; + } + if (cmd.compareTo(".echo") == 0) { + if (args.length > 0 && + (args[0].startsWith("y") || args[0].startsWith("on"))) { + echo = true; + } + return; + } + if (cmd.compareTo(".exit") == 0) { + try { + db.close(); + } catch (Exception e) { + } + System.exit(0); + } + if (cmd.compareTo(".header") == 0) { + if (args.length > 0 && + (args[0].startsWith("y") || args[0].startsWith("on"))) { + showHeader = true; + } + return; + } + if (cmd.compareTo(".help") == 0) { + pw.println(".dump ?TABLE? ... Dump database in text fmt"); + pw.println(".echo ON|OFF Command echo on or off"); + pw.println(".enc ?NAME? Change encoding"); + pw.println(".exit Exit program"); + pw.println(".header ON|OFF Display headers on or off"); + pw.println(".help This message"); + pw.println(".mode MODE Set output mode to\n" + + " line, column, insert\n" + + " list, or html"); + pw.println(".mode insert TABLE Generate SQL insert stmts"); + pw.println(".schema ?PATTERN? List table schema"); + pw.println(".separator STRING Set separator string"); + pw.println(".tables ?PATTERN? List table names"); + return; + } + if (cmd.compareTo(".mode") == 0) { + if (args.length > 0) { + if (args[0].compareTo("line") == 0) { + mode = Shell.MODE_Line; + } else if (args[0].compareTo("column") == 0) { + mode = Shell.MODE_Column; + } else if (args[0].compareTo("list") == 0) { + mode = Shell.MODE_List; + } else if (args[0].compareTo("html") == 0) { + mode = Shell.MODE_Html; + } else if (args[0].compareTo("insert") == 0) { + mode = Shell.MODE_Insert; + if (args.length > 1) { + destTable = args[1]; + } + } + } + return; + } + if (cmd.compareTo(".separator") == 0) { + if (args.length > 0) { + sep = args[0]; + } + return; + } + if (cmd.compareTo(".tables") == 0) { + TableResult t = null; + if (args.length > 0) { + try { + String qarg[] = new String[1]; + qarg[0] = args[0]; + t = db.get_table("SELECT name FROM sqlite_master " + + "WHERE type='table' AND " + + "name LIKE '%%%q%%' " + + "ORDER BY name", qarg); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } else { + try { + t = db.get_table("SELECT name FROM sqlite_master " + + "WHERE type='table' ORDER BY name"); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + if (t != null) { + for (i = 0; i < t.nrows; i++) { + String tab = ((String[]) t.rows.elementAt(i))[0]; + if (tab != null) { + pw.println(tab); + } + } + } + return; + } + if (cmd.compareTo(".schema") == 0) { + if (args.length > 0) { + try { + String qarg[] = new String[1]; + qarg[0] = args[0]; + db.exec("SELECT sql FROM sqlite_master " + + "WHERE type!='meta' AND " + + "name LIKE '%%%q%%' AND " + + "sql NOTNULL " + + "ORDER BY type DESC, name", + this, qarg); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } else { + try { + db.exec("SELECT sql FROM sqlite_master " + + "WHERE type!='meta' AND " + + "sql NOTNULL " + + "ORDER BY tbl_name, type DESC, name", + this); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + return; + } + if (cmd.compareTo(".enc") == 0) { + try { + db.set_encoding(args.length > 0 ? args[0] : null); + } catch (Exception e) { + err.println("" + e); + err.flush(); + } + return; + } + err.println("Unknown command '" + cmd + "'"); + err.flush(); + } + + String read_line(BufferedReader is, String prompt) { + try { + if (prompt != null) { + pw.print(prompt); + pw.flush(); + } + String line = is.readLine(); + return line; + } catch (IOException e) { + return null; + } + } + + void do_input(BufferedReader is) { + String line, sql = null; + String prompt = "SQLITE> "; + while ((line = read_line(is, prompt)) != null) { + if (echo) { + pw.println(line); + } + if (line.length() > 0 && line.charAt(0) == '.') { + do_meta(line); + } else { + if (sql == null) { + sql = line; + } else { + sql = sql + " " + line; + } + if (Database.complete(sql)) { + try { + db.exec(sql, this); + } catch (Exception e) { + if (!echo) { + err.println(sql); + } + err.println("SQL Error: " + e); + err.flush(); + } + sql = null; + prompt = "SQLITE> "; + } else { + prompt = "SQLITE? "; + } + } + pw.flush(); + } + if (sql != null) { + err.println("Incomplete SQL: " + sql); + err.flush(); + } + } + + void do_cmd(String sql) { + if (db == null) { + return; + } + if (sql.length() > 0 && sql.charAt(0) == '.') { + do_meta(sql); + } else { + try { + db.exec(sql, this); + } catch (Exception e) { + err.println("SQL Error: " + e); + err.flush(); + } + } + } + + public static void main(String args[]) { + Shell s = new Shell(System.out, System.err); + s.mode = Shell.MODE_List; + s.sep = "|"; + s.showHeader = false; + s.db = new Database(); + String dbname = null, sql = null; + for (int i = 0; i < args.length; i++) { + if(args[i].compareTo("-html") ==0) { + s.mode = Shell.MODE_Html; + } else if (args[i].compareTo("-list") == 0) { + s.mode = Shell.MODE_List; + } else if (args[i].compareTo("-line") == 0) { + s.mode = Shell.MODE_Line; + } else if (i < args.length - 1 && + args[i].compareTo("-separator") == 0) { + ++i; + s.sep = args[i]; + } else if (args[i].compareTo("-header") == 0) { + s.showHeader = true; + } else if (args[i].compareTo("-noheader") == 0) { + s.showHeader = false; + } else if (args[i].compareTo("-echo") == 0) { + s.echo = true; + } else if (dbname == null) { + dbname = args[i]; + } else if (sql == null) { + sql = args[i]; + } else { + System.err.println("Arguments: ?OPTIONS? FILENAME ?SQL?"); + System.exit(1); + } + } + if (dbname == null) { + System.err.println("No database file given"); + System.exit(1); + } + try { + s.db.open(dbname, 0); + } catch (Exception e) { + System.err.println("Unable to open database: " + e); + System.exit(1); + } + if (sql != null) { + s.do_cmd(sql); + } else { + // BEGIN android-modified + BufferedReader is = + new BufferedReader(new InputStreamReader(System.in), 8192); + // END android-modified + s.do_input(is); + } + try { + s.db.close(); + } catch (Exception ee) { + } + } +} + +/** + * Internal class for dumping an entire database. + * It contains a special callback interface to traverse the + * tables of the current database and output create SQL statements + * and for the data insert SQL statements. + */ + +class DBDump implements Callback { + Shell s; + + DBDump(Shell s, String tables[]) { + this.s = s; + s.pw.println("BEGIN TRANSACTION;"); + if (tables == null || tables.length == 0) { + try { + s.db.exec("SELECT name, type, sql FROM sqlite_master " + + "WHERE type!='meta' AND sql NOT NULL " + + "ORDER BY substr(type,2,1), name", this); + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + } + } else { + String arg[] = new String[1]; + for (int i = 0; i < tables.length; i++) { + arg[0] = tables[i]; + try { + s.db.exec("SELECT name, type, sql FROM sqlite_master " + + "WHERE tbl_name LIKE '%q' AND type!='meta' " + + " AND sql NOT NULL " + + " ORDER BY substr(type,2,1), name", + this, arg); + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + } + } + } + s.pw.println("COMMIT;"); + } + + public void columns(String col[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public void types(String args[]) { + /* Empty body to satisfy SQLite.Callback interface. */ + } + + public boolean newrow(String args[]) { + if (args.length != 3) { + return true; + } + s.pw.println(args[2] + ";"); + if (args[1].compareTo("table") == 0) { + Shell s2 = (Shell) s.clone(); + s2.mode = Shell.MODE_Insert; + s2.set_table_name(args[0]); + String qargs[] = new String[1]; + qargs[0] = args[0]; + try { + if (s2.db.is3()) { + TableResult t = null; + t = s2.db.get_table("PRAGMA table_info('%q')", qargs); + String query; + if (t != null) { + StringBuffer sb = new StringBuffer(); + String sep = ""; + + sb.append("SELECT "); + for (int i = 0; i < t.nrows; i++) { + String col = ((String[]) t.rows.elementAt(i))[1]; + sb.append(sep + "quote(" + + Shell.sql_quote_dbl(col) + ")"); + sep = ","; + } + sb.append(" from '%q'"); + query = sb.toString(); + s2.mode = Shell.MODE_Insert2; + } else { + query = "SELECT * from '%q'"; + } + s2.db.exec(query, s2, qargs); + } else { + s2.db.exec("SELECT * from '%q'", s2, qargs); + } + } catch (Exception e) { + s.err.println("SQL Error: " + e); + s.err.flush(); + return true; + } + } + return false; + } +} diff --git a/sql/src/main/java/SQLite/Stmt.java b/sql/src/main/java/SQLite/Stmt.java new file mode 100644 index 0000000..c4f72ed --- /dev/null +++ b/sql/src/main/java/SQLite/Stmt.java @@ -0,0 +1,288 @@ +package SQLite; + +/** + * Class to represent compiled SQLite3 statement. + * + * Note, that all native methods of this class are + * not synchronized, i.e. it is up to the caller + * to ensure that only one thread is in these + * methods at any one time. + */ + +public class Stmt { + + /** + * Internal handle for the SQLite3 statement. + */ + + private long handle = 0; + + /** + * Internal last error code for prepare()/step() methods. + */ + + protected int error_code = 0; + + /** + * Prepare the next SQL statement for the Stmt instance. + * @return true when the next piece of the SQL statement sequence + * has been prepared, false on end of statement sequence. + */ + + public native boolean prepare() throws SQLite.Exception; + + /** + * Perform one step of compiled SQLite3 statement. + * + * Example:<BR> + * <PRE> + * ... + * try { + * Stmt s = db.prepare("select * from x; select * from y;"); + * s.bind(...); + * ... + * s.bind(...); + * while (s.step(cb)) { + * Object o = s.value(...); + * ... + * } + * // s.reset() for re-execution or + * // s.prepare() for the next piece of SQL + * while (s.prepare()) { + * s.bind(...); + * ... + * s.bind(...); + * while (s.step(cb)) { + * Object o = s.value(...); + * ... + * } + * } + * } catch (SQLite.Exception e) { + * s.close(); + * } + * </PRE> + * + * @return true when row data is available, false on end + * of result set. + */ + + public native boolean step() throws SQLite.Exception; + + /** + * Close the compiled SQLite3 statement. + */ + + public native void close() throws SQLite.Exception; + + /** + * Reset the compiled SQLite3 statement without + * clearing parameter bindings. + */ + + public native void reset() throws SQLite.Exception; + + /** + * Clear all bound parameters of the compiled SQLite3 statement. + */ + + public native void clear_bindings() throws SQLite.Exception; + + /** + * Bind positional integer value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, int value) throws SQLite.Exception; + + /** + * Bind positional long value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, long value) throws SQLite.Exception; + + /** + * Bind positional double value to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter + */ + + public native void bind(int pos, double value) throws SQLite.Exception; + + /** + * Bind positional byte array to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter, may be null + */ + + public native void bind(int pos, byte[] value) throws SQLite.Exception; + + /** + * Bind positional String to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param value value of parameter, may be null + */ + + public native void bind(int pos, String value) throws SQLite.Exception; + + /** + * Bind positional SQL null to compiled SQLite3 statement. + * @param pos parameter index, 1-based + */ + + public native void bind(int pos) throws SQLite.Exception; + + /** + * Bind positional zero'ed blob to compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @param length byte size of zero blob + */ + + public native void bind_zeroblob(int pos, int length) + throws SQLite.Exception; + + /** + * Return number of parameters in compiled SQLite3 statement. + * @return int number of parameters + */ + + public native int bind_parameter_count() throws SQLite.Exception; + + /** + * Return name of parameter in compiled SQLite3 statement. + * @param pos parameter index, 1-based + * @return String parameter name + */ + + public native String bind_parameter_name(int pos) throws SQLite.Exception; + + /** + * Return index of named parameter in compiled SQLite3 statement. + * @param name of parameter + * @return int index of parameter, 1-based + */ + + public native int bind_parameter_index(String name) + throws SQLite.Exception; + + + /** + * Retrieve integer column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return int column value + */ + + public native int column_int(int col) throws SQLite.Exception; + + /** + * Retrieve long column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return long column value + */ + public native long column_long(int col) throws SQLite.Exception; + + /** + * Retrieve double column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return double column value + */ + public native double column_double(int col) throws SQLite.Exception; + + /** + * Retrieve blob column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return byte[] column value + */ + public native byte[] column_bytes(int col) throws SQLite.Exception; + + /** + * Retrieve string column from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return String column value + */ + public native String column_string(int col) throws SQLite.Exception; + + /** + * Retrieve column type from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return column type code, e.g. SQLite.Constants.SQLITE_INTEGER + */ + public native int column_type(int col) throws SQLite.Exception; + + /** + * Retrieve number of columns of exec'ed SQLite3 statement. + * @return int number of columns + */ + + public native int column_count() throws SQLite.Exception; + + /** + * Retrieve column data as object from exec'ed SQLite3 statement. + * @param col column number, 0-based + * @return Object or null + */ + + public Object column(int col) throws SQLite.Exception { + switch (column_type(col)) { + case Constants.SQLITE_INTEGER: + return new Long(column_long(col)); + case Constants.SQLITE_FLOAT: + return new Double(column_double(col)); + case Constants.SQLITE_BLOB: + return column_bytes(col); + case Constants.SQLITE3_TEXT: + return column_string(col); + } + return null; + } + + /** + * Return table name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_table_name(int col) throws SQLite.Exception; + + /** + * Return database name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_database_name(int col) throws SQLite.Exception; + + /** + * Return declared column type of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_decltype(int col) throws SQLite.Exception; + + /** + * Return origin column name of column of SQLite3 statement. + * @param col column number, 0-based + * @return String or null + */ + + public native String column_origin_name(int col) throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sql/src/main/java/SQLite/StringEncoder.java b/sql/src/main/java/SQLite/StringEncoder.java new file mode 100644 index 0000000..c2f20ad --- /dev/null +++ b/sql/src/main/java/SQLite/StringEncoder.java @@ -0,0 +1,201 @@ +package SQLite; + +/** + * String encoder/decoder for SQLite. + * + * This module was kindly donated by Eric van der Maarel of Nedap N.V. + * + * This encoder was implemented based on an original idea from an anonymous + * author in the source code of the SQLite distribution. + * I feel obliged to provide a quote from the original C-source code: + * + * "The author disclaims copyright to this source code. In place of + * a legal notice, here is a blessing: + * + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give." + * + */ + +public class StringEncoder { + + /** + * Encodes the given byte array into a string that can be used by + * the SQLite database. The database cannot handle null (0x00) and + * the character '\'' (0x27). The encoding consists of escaping + * these characters with a reserved character (0x01). The escaping + * is applied after determining and applying a shift that minimizes + * the number of escapes required. + * With this encoding the data of original size n is increased to a + * maximum of 1+(n*257)/254. + * For sufficiently large n the overhead is thus less than 1.2%. + * @param a the byte array to be encoded. A null reference is handled as + * an empty array. + * @return the encoded bytes as a string. When an empty array is + * provided a string of length 1 is returned, the value of + * which is bogus. + * When decoded with this class' <code>decode</code> method + * a string of size 1 will return an empty byte array. + */ + + public static String encode(byte[] a) { + // check input + if (a == null || a.length == 0) { + // bogus shift, no data + return "x"; + } + // determine count + int[] cnt = new int[256]; + for (int i = 0 ; i < a.length; i++) { + cnt[a[i] & 0xff]++; + } + // determine shift for minimum number of escapes + int shift = 1; + int nEscapes = a.length; + for (int i = 1; i < 256; i++) { + if (i == '\'') { + continue; + } + int sum = cnt[i] + cnt[(i + 1) & 0xff] + cnt[(i + '\'') & 0xff]; + if (sum < nEscapes) { + nEscapes = sum; + shift = i; + if (nEscapes == 0) { + // cannot become smaller + break; + } + } + } + // construct encoded output + int outLen = a.length + nEscapes + 1; + StringBuffer out = new StringBuffer(outLen); + out.append((char)shift); + for (int i = 0; i < a.length; i++) { + // apply shift + char c = (char)((a[i] - shift)&0xff); + // insert escapes + if (c == 0) { // forbidden + out.append((char)1); + out.append((char)1); + } else if (c == 1) { // escape character + out.append((char)1); + out.append((char)2); + } else if (c == '\'') { // forbidden + out.append((char)1); + out.append((char)3); + } else { + out.append(c); + } + } + return out.toString(); + } + + /** + * Decodes the given string that is assumed to be a valid encoding + * of a byte array. Typically the given string is generated by + * this class' <code>encode</code> method. + * @param s the given string encoding. + * @return the byte array obtained from the decoding. + * @throws IllegalArgumentException when the string given is not + * a valid encoded string for this encoder. + */ + + public static byte[] decode(String s) { + char[] a = s.toCharArray(); + if (a.length > 2 && a[0] == 'X' && + a[1] == '\'' && a[a.length-1] == '\'') { + // SQLite3 BLOB syntax + byte[] result = new byte[(a.length-3)/2]; + for (int i = 2, k = 0; i < a.length - 1; i += 2, k++) { + byte tmp = (byte) (a[i] - '0'); + if (tmp > 15) { + tmp -= 0x20; + } + result[k] = (byte) (tmp << 4); + tmp = (byte) (a[i+1] - '0'); + if (tmp > 15) { + tmp -= 0x20; + } + result[k] |= tmp; + } + return result; + } + // first element is the shift + byte[] result = new byte[a.length-1]; + int i = 0; + int shift = s.charAt(i++); + int j = 0; + while (i < s.length()) { + int c; + if ((c = s.charAt(i++)) == 1) { // escape character found + if ((c = s.charAt(i++)) == 1) { + c = 0; + } else if (c == 2) { + c = 1; + } else if (c == 3) { + c = '\''; + } else { + throw new IllegalArgumentException( + "invalid string passed to decoder: " + j); + } + } + // do shift + result[j++] = (byte)((c + shift) & 0xff); + } + int outLen = j; + // provide array of correct length + if (result.length != outLen) { + result = byteCopy(result, 0, outLen, new byte[outLen]); + } + return result; + } + + /** + * Copies count elements from source, starting at element with + * index offset, to the given target. + * @param source the source. + * @param offset the offset. + * @param count the number of elements to be copied. + * @param target the target to be returned. + * @return the target being copied to. + */ + + private static byte[] byteCopy(byte[] source, int offset, + int count, byte[] target) { + for (int i = offset, j = 0; i < offset + count; i++, j++) { + target[j] = source[i]; + } + return target; + } + + + static final char[] xdigits = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + + /** + * Encodes the given byte array into SQLite3 blob notation, ie X'..' + * @param a the byte array to be encoded. A null reference is handled as + * an empty array. + * @return the encoded bytes as a string. + */ + + public static String encodeX(byte[] a) { + // check input + if (a == null || a.length == 0) { + return "X''"; + } + int outLen = a.length + 3; + StringBuffer out = new StringBuffer(outLen); + out.append('X'); + out.append('\''); + for (int i = 0; i < a.length; i++) { + out.append(xdigits[a[i] >> 4]); + out.append(xdigits[a[i] & 0x0F]); + } + out.append('\''); + return out.toString(); + } +} diff --git a/sql/src/main/java/SQLite/TableResult.java b/sql/src/main/java/SQLite/TableResult.java new file mode 100644 index 0000000..1a7fb57 --- /dev/null +++ b/sql/src/main/java/SQLite/TableResult.java @@ -0,0 +1,133 @@ +package SQLite; + +import java.util.Vector; + +/** + * Class representing an SQLite result set as + * returned by the + * <A HREF="Database.html#get_table(java.lang.String)">Database.get_table</A> + * convenience method. + * <BR><BR> + * Example:<BR> + * + * <PRE> + * ... + * SQLite.Database db = new SQLite.Database(); + * db.open("db", 0); + * System.out.print(db.get_table("select * from TEST")); + * ... + * </PRE> + * Example output:<BR> + * + * <PRE> + * id|firstname|lastname| + * 0|John|Doe| + * 1|Speedy|Gonzales| + * ... + * </PRE> + */ + +public class TableResult implements Callback { + + /** + * Number of columns in the result set. + */ + + public int ncolumns; + + /** + * Number of rows in the result set. + */ + + public int nrows; + + /** + * Column names of the result set. + */ + + public String column[]; + + /** + * Types of columns of the result set or null. + */ + + public String types[]; + + /** + * Rows of the result set. Each row is stored as a String array. + */ + + public Vector rows; + + /** + * Create an empty result set. + */ + + public TableResult() { + clear(); + } + + /** + * Clear result set. + */ + + public void clear() { + column = new String[0]; + types = null; + rows = new Vector(); + ncolumns = nrows = 0; + } + + /** + * Callback method used while the query is executed. + */ + + public void columns(String coldata[]) { + column = coldata; + ncolumns = column.length; + } + + /** + * Callback method used while the query is executed. + */ + + public void types(String types[]) { + this.types = types; + } + + /** + * Callback method used while the query is executed. + */ + + public boolean newrow(String rowdata[]) { + if (rowdata != null) { + rows.addElement(rowdata); + nrows++; + } + return false; + } + + /** + * Make String representation of result set. + */ + + public String toString() { + StringBuffer sb = new StringBuffer(); + int i; + for (i = 0; i < ncolumns; i++) { + sb.append(column[i] == null ? "NULL" : column[i]); + sb.append('|'); + } + sb.append('\n'); + for (i = 0; i < nrows; i++) { + int k; + String row[] = (String[]) rows.elementAt(i); + for (k = 0; k < ncolumns; k++) { + sb.append(row[k] == null ? "NULL" : row[k]); + sb.append('|'); + } + sb.append('\n'); + } + return sb.toString(); + } +} diff --git a/sql/src/main/java/SQLite/Trace.java b/sql/src/main/java/SQLite/Trace.java new file mode 100644 index 0000000..19ed2a1 --- /dev/null +++ b/sql/src/main/java/SQLite/Trace.java @@ -0,0 +1,17 @@ +package SQLite; + +/** + * Callback interface for SQLite's trace function. + */ + +public interface Trace { + + /** + * Callback to trace (ie log) one SQL statement. + * + * @param stmt SQL statement string + */ + + public void trace(String stmt); +} + diff --git a/sql/src/main/java/SQLite/Vm.java b/sql/src/main/java/SQLite/Vm.java new file mode 100644 index 0000000..9856ed0 --- /dev/null +++ b/sql/src/main/java/SQLite/Vm.java @@ -0,0 +1,78 @@ +package SQLite; + +/** + * Class to represent compiled SQLite VM. + */ + +public class Vm { + + /** + * Internal handle for the compiled SQLite VM. + */ + + private long handle = 0; + + /** + * Internal last error code for compile()/step() methods. + */ + + protected int error_code = 0; + + /** + * Perform one step on compiled SQLite VM. + * The result row is passed to the given callback interface.<BR><BR> + * + * Example:<BR> + * <PRE> + * ... + * try { + * Vm vm = db.compile("select * from x; select * from y;"); + * while (vm.step(cb)) { + * ... + * } + * while (vm.compile()) { + * while (vm.step(cb)) { + * ... + * } + * } + * } catch (SQLite.Exception e) { + * } + * </PRE> + * + * @param cb the object implementing the callback methods. + * @return true as long as more row data can be retrieved, + * false, otherwise. + */ + + public native boolean step(Callback cb) throws SQLite.Exception; + + /** + * Compile the next SQL statement for the SQLite VM instance. + * @return true when SQL statement has been compiled, false + * on end of statement sequence. + */ + + public native boolean compile() throws SQLite.Exception; + + /** + * Abort the compiled SQLite VM. + */ + + public native void stop() throws SQLite.Exception; + + /** + * Destructor for object. + */ + + protected native void finalize(); + + /** + * Internal native initializer. + */ + + private static native void internal_init(); + + static { + internal_init(); + } +} diff --git a/sql/src/main/java/java/sql/Array.java b/sql/src/main/java/java/sql/Array.java new file mode 100644 index 0000000..e1d903e --- /dev/null +++ b/sql/src/main/java/java/sql/Array.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Map; + +/** + * A Java representation of the SQL ARRAY type. + */ +public interface Array { + + /** + * Retrieves the contents of the SQL ARRAY value as a Java array object. + * + * @return A Java array containing the elements of this Array + * @throws SQLException + */ + public Object getArray() throws SQLException; + + /** + * Returns part of the SQL ARRAY associated with this Array, starting at a + * particular index and comprising up to count successive elements of the + * SQL array. + * + * @param index + * @param count + * @return A Java array containing the subportion of elements of this Array + * @throws SQLException + */ + public Object getArray(long index, int count) throws SQLException; + + /** + * Returns part of the SQL ARRAY associated with this Array, starting at a + * particular index and comprising up to count successive elements of the + * SQL array. + * + * @param index + * @param count + * @param map + * @return A Java array containing the subportion of elements of this Array + * @throws SQLException + */ + public Object getArray(long index, int count, Map<String, Class<?>> map) + throws SQLException; + + /** + * Returns the SQL ARRAY associated with this Array. + * + * @param map + * @return A Java array containing the elements of this Array + * @throws SQLException + */ + public Object getArray(Map<String, Class<?>> map) throws SQLException; + + /** + * Returns the JDBC type of the entries in this Array's associated array. + * + * @return An integer constant from the java.sql.Types class + * @throws SQLException + */ + public int getBaseType() throws SQLException; + + /** + * Returns the SQL type name of the entries in the array associated with + * this Array. + * + * @return The database specific name or a fully-qualified SQL type name. + * @throws SQLException + */ + public String getBaseTypeName() throws SQLException; + + /** + * Returns a ResultSet object which holds the entries of the SQL ARRAY + * associated with this Array. + * + * @return the ResultSet + * @throws SQLException + */ + public ResultSet getResultSet() throws SQLException; + + /** + * Returns a ResultSet object that holds the entries of a subarray, + * beginning at a particular index and comprising up to count successive + * entries. + * + * @param index + * @param count + * @return the ResultSet + * @throws SQLException + */ + public ResultSet getResultSet(long index, int count) throws SQLException; + + /** + * Returns a ResultSet object that holds the entries of a subarray, + * beginning at a particular index and comprising up to count successive + * entries. + * + * @param index + * @param count + * @param map + * @return the ResultSet + * @throws SQLException + */ + public ResultSet getResultSet(long index, int count, + Map<String, Class<?>> map) throws SQLException; + + /** + * Returns a ResultSet object which holds the entries of the SQL ARRAY + * associated with this Array. + * + * @param map + * @return the ResultSet + * @throws SQLException + */ + public ResultSet getResultSet(Map<String, Class<?>> map) + throws SQLException; + +} diff --git a/sql/src/main/java/java/sql/BatchUpdateException.java b/sql/src/main/java/java/sql/BatchUpdateException.java new file mode 100644 index 0000000..f39dc5e --- /dev/null +++ b/sql/src/main/java/java/sql/BatchUpdateException.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.Serializable; + +/** + * An exception thrown if a problem occurs during a batch update operation. + * <p> + * A BatchUpdateException provides additional information about the problem that + * occurred, compared with a standard SQLException. It supplies update counts + * for successful commands that executed within the batch update, but before the + * exception was encountered. + * <p> + * The element order in the array of update counts matches the order that the + * commands were added to the batch operation. + * <p> + * Once a batch update command fails and a BatchUpdateException is thrown, the + * JDBC driver may continue processing the remaining commands in the batch. If + * the driver does process more commands after the problem occurs, the array + * returned by BatchUpdateException.getUpdateCounts has an element for every + * command in the batch, not only those that executed successfully. In this + * case, the array element for any command which encountered a problem is set to + * Statement.EXECUTE_FAILED. + */ +public class BatchUpdateException extends SQLException implements Serializable { + + private static final long serialVersionUID = 5977529877145521757L; + + private int[] updateCounts = null; + + /** + * Creates a BatchUpdateException with the Reason, SQLState, and Update + * Counts set to null and a Vendor Code of 0. + */ + public BatchUpdateException() { + super(); + } + + /** + * Creates a BatchUpdateException with the Update Counts set to the supplied + * value and the Reason, SQLState set to null and a Vendor Code of 0. + * + * @param updateCounts + * the array of Update Counts to use in initialization + */ + public BatchUpdateException(int[] updateCounts) { + super(); + this.updateCounts = updateCounts; + } + + /** + * Creates a BatchUpdateException with the Update Counts set to the supplied + * value, the Reason set to the supplied value and SQLState set to null and + * a Vendor Code of 0. + * + * @param reason + * the initialization value for Reason + * @param updateCounts + * the array of Update Counts to set + */ + public BatchUpdateException(String reason, int[] updateCounts) { + super(reason); + this.updateCounts = updateCounts; + } + + /** + * Creates a BatchUpdateException with the Update Counts set to the supplied + * value, the Reason set to the supplied value, the SQLState initialized to + * the supplied value and the Vendor Code initialized to 0. + * + * @param reason + * the value to use for the Reason + * @param SQLState + * the X/OPEN value to use for the SQLState + * @param updateCounts + * the array of Update Counts to set + */ + public BatchUpdateException(String reason, String SQLState, + int[] updateCounts) { + super(reason, SQLState); + this.updateCounts = updateCounts; + } + + /** + * Creates a BatchUpdateException with the Update Counts set to the supplied + * value, the Reason set to the supplied value, the SQLState initialized to + * the supplied value and the Vendor Code set to the supplied value. + * + * @param reason + * the value to use for the Reason + * @param SQLState + * the X/OPEN value to use for the SQLState + * @param vendorCode + * the value to use for the vendor error code + * @param updateCounts + * the array of Update Counts to set + */ + public BatchUpdateException(String reason, String SQLState, int vendorCode, + int[] updateCounts) { + super(reason, SQLState, vendorCode); + this.updateCounts = updateCounts; + } + + /** + * Gets the Update Counts array. + * <p> + * If a batch update command fails and a BatchUpdateException is thrown, the + * JDBC driver may continue processing the remaining commands in the batch. + * If the driver does process more commands after the problem occurs, the + * array returned by <code>BatchUpdateException.getUpdateCounts</code> has + * an element for every command in the batch, not only those that executed + * successfully. In this case, the array element for any command which + * encountered a problem is set to Statement.EXECUTE_FAILED. + * + * @return an array that contains the successful update counts, before this + * exception. Alternatively, if the driver continues to process + * commands following an error, one of these listed items for every + * command the batch contains: + * <ol> + * <li>an count of the updates</li> + * <li><code>Statement.SUCCESS_NO_INFO</code> indicating that the + * command completed successfully, but the amount of altered rows is + * not known.</li> + * <li><code>Statement.EXECUTE_FAILED</code> indicating that the + * command was unsuccessful. + * </ol> + */ + public int[] getUpdateCounts() { + return updateCounts; + } +} diff --git a/sql/src/main/java/java/sql/Blob.java b/sql/src/main/java/java/sql/Blob.java new file mode 100644 index 0000000..2b3cff5 --- /dev/null +++ b/sql/src/main/java/java/sql/Blob.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.OutputStream; +import java.io.InputStream; + +/** + * A Java interface mapping for the SQL BLOB type. + * <p> + * An SQL CLOB type stores a large array of bytes (binary data) as the value in + * a column of a database. + * <p> + * The java.sql.Blob interface provides methods for setting and retrieving data + * in the Blob, for querying Clob data length, for searching for data within the + * Blob. + */ +public interface Blob { + + /** + * Retrieves this Blob object as a binary stream. + * + * @return a binary InputStream giving access to the Blob data + * @throws SQLException + * if an error occurs accessing the Blob + */ + public InputStream getBinaryStream() throws SQLException; + + /** + * Gets a portion of the value of this Blob as an array of bytes. + * + * @param pos + * the position of the first byte in the Blob to get, where the + * first byte in the Blob has position = 1 + * @param length + * the number of bytes to get + * @return a byte array containing the data from the Blob, starting at pos + * and of length up to <code>length</code> bytes long + * @throws SQLException + * if an error occurs accessing the Blob + */ + public byte[] getBytes(long pos, int length) throws SQLException; + + /** + * Gets the number of bytes in this Blob object. + * + * @return an long value with the length of the Blob in bytes + * @throws SQLException + * if an error occurs accessing the Blob + */ + public long length() throws SQLException; + + /** + * Search for the position in this Blob at which a specified pattern begins, + * starting at a specified position within the Blob. + * + * @param pattern + * a Blob containing the pattern of data to search for in this + * Blob + * @param start + * the position within this Blob to start the search, where the + * first position in the Blob is 1 + * @return a long value with the position at which the pattern begins. -1 if + * the pattern is not found in this Blob. + * @throws SQLException + * if an error occurs accessing the Blob + */ + public long position(Blob pattern, long start) throws SQLException; + + /** + * Search for the position in this Blob at which the specified pattern + * begins, starting at a specified position within the Blob. + * + * @param pattern + * a byte array containing the pattern of data to search for in + * this Blob + * @param start + * the position within this Blob to start the search, where the + * first position in the Blob is 1 + * @return a long value with the position at which the pattern begins. -1 if + * the pattern is not found in this Blob. + * @throws SQLException + * if an error occurs accessing the Blob + */ + public long position(byte[] pattern, long start) throws SQLException; + + /** + * Gets a stream that can be used to write binary data to this Blob. + * + * @param pos + * the position within this Blob at which to start writing, where + * the first position in the Blob is 1 + * @return a binary InputStream which can be used to write data into the + * Blob starting at the specified position. + * @throws SQLException + * if an error occurs accessing the Blob + */ + public OutputStream setBinaryStream(long pos) throws SQLException; + + /** + * Writes a specified array of bytes to this Blob. object, starting at a + * specified position. Returns the number of bytes written. + * + * @param pos + * the position within this Blob at which to start writing, where + * the first position in the Blob is 1 + * @param theBytes + * an array of bytes to write into the Blob + * @return an integer containing the number of bytes written to the Blob + * @throws SQLException + * if an error occurs accessing the Blob + */ + public int setBytes(long pos, byte[] theBytes) throws SQLException; + + /** + * Writes a portion of a specified byte array to this Blob. Returns the + * number of bytes written. + * + * @param pos + * the position within this Blob at which to start writing, where + * the first position in the Blob is 1 + * @param theBytes + * an array of bytes to write into the Blob + * @param offset + * the offset into the byte array from which to start writing + * data - the first byte in the array has offset 0. + * @param len + * the length of data to write, as the number of bytes + * @return an integer containing the number of bytes written to the Blob + * @throws SQLException + * if an error occurs accessing the Blob + */ + public int setBytes(long pos, byte[] theBytes, int offset, int len) + throws SQLException; + + /** + * Truncate the value of this Blob object to a specified length in bytes. + * + * @param len + * the length of data in bytes to truncate the value of this Blob + * @throws SQLException + * if an error occurs accessing the Blob + */ + public void truncate(long len) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/CallableStatement.java b/sql/src/main/java/java/sql/CallableStatement.java new file mode 100644 index 0000000..2097277 --- /dev/null +++ b/sql/src/main/java/java/sql/CallableStatement.java @@ -0,0 +1,1302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Map; +import java.net.URL; +import java.io.InputStream; +import java.io.Reader; + +/** + * An interface used to call Stored Procedures. + * <p> + * The JDBC API provides an SQL escape syntax allowing Stored Procedures to be + * called in a standard way for all databases. The JDBC escape syntax has two + * forms. One form includes a result parameter. The second form does not include + * a result parameter. Where the result parameter is used, it must be declared + * as an OUT parameter. Other parameters can be declared as IN, OUT or INOUT. + * Parameters are referenced either by name or by a numerical index, with the + * first parameter being 1, the second 1 and so on. Here are examples of the two + * forms of the escape syntax: <code> + * + * { ?= call <.procedurename>.[([parameter1,parameter2,...])]} + * + * {call <.procedurename>.[([parameter1,parameter2,...])]} + * </code> + * <p> + * IN parameters are set before calling the procedure, using the setter methods + * which are inherited from <code>PreparedStatement</code>. For OUT + * parameters, their Type must be registered before executing the stored + * procedure, and the value is retrieved using the getter methods defined in the + * CallableStatement interface. + * <p> + * CallableStatements can return one or more ResultSets. Where multiple + * ResultSets are returned they are accessed using the methods inherited from + * the <code>Statement</code> interface. + */ +public interface CallableStatement extends PreparedStatement { + + /** + * Gets the value of a specified JDBC <code>ARRAY</code> parameter as a + * java.sql.Array. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Array containing the parameter value + * @throws SQLException + * if a database error happens + */ + public Array getArray(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC ARRAY parameter as a java.sql.Array. + * + * @param parameterName + * the parameter of interest's name + * @return a <code>java.sql.Array</code> containing the parameter value + * @throws SQLException + * if there is a problem accessing the database + */ + public Array getArray(String parameterName) throws SQLException; + + /** + * Returns a new {@link BigDecimal} representation of the JDBC + * <code>NUMERIC</code> parameter specified by the input index. + * + * @param parameterIndex + * the parameter number index (starts from 1) + * @return a <code>java.math.BigDecimal</code> with the value of the + * specified parameter. The value <code>null</code> is returned if + * the parameter in question is an SQL <code>NULL</code> + * @throws SQLException + * if there is a problem accessing the database + */ + public BigDecimal getBigDecimal(int parameterIndex) throws SQLException; + + /** + * Returns a new {@link BigDecimal} representation of the JDBC + * <code>NUMERIC</code> parameter specified by the input index. The number + * of digits after the decimal point is specified by <code>scale</code>. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param scale + * the number of digits after the decimal point to get + * @return a <code>java.math.BigDecimal</code> with the value of the + * specified parameter. The value <code>null</code> is returned if + * the parameter in question is an SQL <code>NULL</code> + * @throws SQLException + * if there is a problem accessing the database + * @deprecated Use {@link #getBigDecimal(int)} or {@link #getBigDecimal(String)} + */ + @Deprecated + public BigDecimal getBigDecimal(int parameterIndex, int scale) + throws SQLException; + + /** + * Returns a new {@link BigDecimal} representation of the JDBC + * <code>NUMERIC</code> parameter specified by the input name. + * + * @param parameterName + * the name of the parameter + * @return a java.math.BigDecimal with the value of the specified parameter. + * null if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public BigDecimal getBigDecimal(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC BLOB parameter as a java.sql.Blob + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Blob with the value. null if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Blob getBlob(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC BLOB parameter as a java.sql.Blob + * + * @param parameterName + * the name of the parameter + * @return a java.sql.Blob with the value. null if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Blob getBlob(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC BIT parameter as a boolean + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a boolean representing the parameter value. false if the value is + * SQL NULL + * @throws SQLException + * if a database error happens + */ + public boolean getBoolean(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC <code>BIT</code> parameter as a + * boolean + * + * @param parameterName + * the parameter of interest's name + * @return a <code>boolean</code> representation of the value of the + * parameter. <code>false</code> is returned if the SQL value is + * <code>NULL</code>. + * @throws SQLException + * if there is a problem accessing the database + */ + public boolean getBoolean(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC TINYINT parameter as a byte + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a byte with the value of the parameter. 0 if the value is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public byte getByte(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC <code>TINYINT</code> parameter as a + * Java <code>byte</code>. + * + * @param parameterName + * the parameter of interest's name + * @return a <code>byte</code> representation of the value of the + * parameter. <code>0</code> is returned if the SQL value is + * <code>NULL</code>. + * @throws SQLException + * if there is a problem accessing the database + */ + public byte getByte(String parameterName) throws SQLException; + + /** + * Returns a byte array representation of the indexed JDBC + * <code>BINARY</code> or <code>VARBINARY</code> parameter. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return an array of bytes with the value of the parameter. null if the + * value is SQL NULL. + * @throws SQLException + * if there is a problem accessing the database + */ + public byte[] getBytes(int parameterIndex) throws SQLException; + + /** + * Returns a byte array representation of the named JDBC <code>BINARY</code> + * or <code>VARBINARY</code> parameter. + * + * @param parameterName + * the name of the parameter + * @return an array of bytes with the value of the parameter. null if the + * value is SQL NULL. + * @throws SQLException + * if there is a problem accessing the database + */ + public byte[] getBytes(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC CLOB parameter as a java.sql.Clob + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Clob with the value of the parameter. null if the + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Clob getClob(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC CLOB parameter as a java.sql.Clob + * + * @param parameterName + * the name of the parameter + * @return a java.sql.Clob with the value of the parameter. null if the + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Clob getClob(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC DATE parameter as a java.sql.Date. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return the java.sql.Date with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC DATE parameter as a java.sql.Date., + * using a specified Calendar to construct the date. + * <p> + * The JDBC driver uses the Calendar to create the Date using a particular + * timezone and locale. Default behaviour of the driver is to use the Java + * virtual machine default settings. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param cal + * the Calendar to use to construct the Date + * @return the java.sql.Date with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(int parameterIndex, Calendar cal) throws SQLException; + + /** + * Gets the value of a specified JDBC DATE parameter as a java.sql.Date. + * + * @param parameterName + * the name of the parameter + * @return the java.sql.Date with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC DATE parameter as a java.sql.Date., + * using a specified Calendar to construct the date. + * <p> + * The JDBC driver uses the Calendar to create the Date using a particular + * timezone and locale. Default behaviour of the driver is to use the Java + * virtual machine default settings. + * + * @param parameterName + * the parameter name + * @param cal + * used for creating the returned <code>Date</code> + * @return the java.sql.Date with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(String parameterName, Calendar cal) throws SQLException; + + /** + * Gets the value of a specified JDBC DOUBLE parameter as a double + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return the double with the parameter value. 0.0 if the value is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public double getDouble(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC DOUBLE parameter as a double + * + * @param parameterName + * the parameter name + * @return the parameter value as represented in a Java <code>double</code>. + * An SQL value of <code>NULL</code> gets represented as + * <code>0</code> (zero). + * @throws SQLException + * if there is a problem accessing the database + */ + public double getDouble(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC FLOAT parameter as a float + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return the float with the parameter value. 0.0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public float getFloat(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC <code>FLOAT</code> parameter as a + * Java <code>float</code>. + * + * @param parameterName + * the parameter name + * @return the parameter value as represented in a Java <code>float</code>. + * An SQL value of <code>NULL</code> gets represented as + * <code>0</code> (zero). + * @throws SQLException + * if there is a problem accessing the database + */ + public float getFloat(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC INTEGER parameter as an int + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return the int with the parameter value. 0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public int getInt(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC INTEGER parameter as an int + * + * @param parameterName + * the name of the parameter + * @return the int with the parameter value. 0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public int getInt(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC BIGINT parameter as a long + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return the long with the parameter value. 0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public long getLong(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC BIGINT parameter as a long + * + * @param parameterName + * the name of the parameter + * @return the long with the parameter value. 0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public long getLong(String parameterName) throws SQLException; + + /** + * Gets the value of a specified parameter as a Java <code>Object</code>. + * <p> + * The object type returned is the JDBC type registered for the parameter + * with a <code>registerOutParameter</code> call. If a parameter was + * registered as a <code>java.sql.Types.OTHER</code> then it may hold + * abstract types that are particular to the connected database. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return an Object holding the value of the parameter. + * @throws SQLException + * if there is a problem accessing the database + */ + public Object getObject(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified parameter as an Object. A Map is supplied + * to provide custom mapping of the parameter value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param map + * the Map holing the mapping from SQL types to Java classes + * @return an Object holding the value of the parameter. + * @throws SQLException + * if a database error happens + */ + public Object getObject(int parameterIndex, Map<String, Class<?>> map) + throws SQLException; + + /** + * Gets the value of a specified parameter as an Object. + * <p> + * The object type returned is the JDBC type registered for the parameter + * with a <code>registerOutParameter</code> call. If a parameter was + * registered as a <code>java.sql.Types.OTHER</code> then it may hold + * abstract types that are particular to the connected database. + * + * @param parameterName + * the parameter name + * @return the Java <code>Object</code> representation of the value of the + * parameter. + * @throws SQLException + * if there is a problem accessing the database + */ + public Object getObject(String parameterName) throws SQLException; + + /** + * Gets the value of a specified parameter as an Object. A Map is supplied + * to provide custom mapping of the parameter value. + * + * @param parameterName + * the parameter name + * @param map + * the <code>Map</code> of SQL types to their Java counterparts + * @return an <code>Object</code> holding the value of the parameter. + * @throws SQLException + * if there is a problem accessing the database + */ + public Object getObject(String parameterName, Map<String, Class<?>> map) + throws SQLException; + + /** + * Gets the value of a specified JDBC REF(<structured type>) parameter as a + * java.sql.Ref + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Ref with the parameter value. null if the value is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public Ref getRef(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC REF(<structured type>) parameter as a + * java.sql.Ref + * + * @param parameterName + * the parameter name + * @return the target parameter's value in the form of a + * <code>java.sql.Ref</code>. A <code>null</code> reference is + * returned for a parameter value of SQL <code>NULL</code>. + * @throws SQLException + * if there is a problem accessing the database + */ + public Ref getRef(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC SMALLINT parameter as a short + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a short with the parameter value. 0 if the value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public short getShort(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC <code>SMALLINT</code> parameter as a + * short + * + * @param parameterName + * the parameter name + * @return the value of the target parameter as a Java <code>short</code>. + * If the value is an SQL <code>NULL</code> then <code>0</code> + * (zero) is returned. + * @throws SQLException + * if there is a problem accessing the database + */ + public short getShort(String parameterName) throws SQLException; + + /** + * Returns the indexed parameter's value as a string. The parameter value + * must be one of the JDBC types <code>CHAR</code>, <code>VARCHAR</code> + * or <code>LONGVARCHAR</code>. + * <p> + * The string corresponding to a <code>CHAR</code> of fixed length will be + * of identical length to the value in the database inclusive of padding + * characters. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a String with the parameter value. null if the value is SQL NULL. + * @throws SQLException + * if there is a problem accessing the database + */ + public String getString(int parameterIndex) throws SQLException; + + /** + * Returns the named parameter's value as a string. The parameter value must + * be one of the JDBC types <code>CHAR</code>, <code>VARCHAR</code> or + * <code>LONGVARCHAR</code>. + * <p> + * The string corresponding to a <code>CHAR</code> of fixed length will be + * of identical length to the value in the database inclusive of padding + * characters. + * + * @param parameterName + * the parameter name + * @return a String with the parameter value. null if the value is SQL NULL. + * @throws SQLException + * if there is a problem accessing the database + */ + public String getString(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC TIME parameter as a java.sql.Time. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Time with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(int parameterIndex) throws SQLException; + + /** + * Gets the value of a specified JDBC TIME parameter as a java.sql.Time, + * using the supplied Calendar to construct the time. The JDBC driver uses + * the Calendar to handle specific timezones and locales when creating the + * Time. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param cal + * the Calendar to use in constructing the Time. + * @return a java.sql.Time with the parameter value. null if the value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(int parameterIndex, Calendar cal) throws SQLException; + + /** + * Gets the value of a specified JDBC <code>TIME</code> parameter as a + * <code>java.sql.Time</code> + * + * @param parameterName + * the parameter name + * @return a new <code>java.sql.Time</code> with the parameter value. A + * <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Time getTime(String parameterName) throws SQLException; + + /** + * Gets the value of a specified JDBC TIME parameter as a java.sql.Time, + * using the supplied Calendar to construct the time. The JDBC driver uses + * the Calendar to handle specific timezones and locales when creating the + * Time. + * + * @param parameterName + * the parameter name + * @param cal + * used for creating the returned <code>Time</code> + * @return a <code>java.sql.Time</code> with the parameter value. A + * <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Time getTime(String parameterName, Calendar cal) throws SQLException; + + /** + * Returns the indexed parameter's <code>TIMESTAMP</code> value as a + * <code>java.sql.Timestamp</code>. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a new <code>java.sql.Timestamp</code> with the parameter value. + * A <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(int parameterIndex) throws SQLException; + + /** + * Returns the indexed parameter's <code>TIMESTAMP</code> value as a + * <code>java.sql.Timestamp</code>. The JDBC driver uses the supplied + * <code>Calendar</code> to handle specific timezones and locales when + * creating the result. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param cal + * used for creating the returned <code>Timestamp</code> + * @return a new <code>java.sql.Timestamp</code> with the parameter value. + * A <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(int parameterIndex, Calendar cal) + throws SQLException; + + /** + * Returns the named parameter's <code>TIMESTAMP</code> value as a + * <code>java.sql.Timestamp</code>. + * + * @param parameterName + * the parameter name + * @return a new <code>java.sql.Timestamp</code> with the parameter value. + * A <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(String parameterName) throws SQLException; + + /** + * Returns the indexed parameter's <code>TIMESTAMP</code> value as a + * <code>java.sql.Timestamp</code>. The JDBC driver uses the supplied + * <code>Calendar</code> to handle specific timezones and locales when + * creating the result. + * + * @param parameterName + * the parameter name + * @param cal + * used for creating the returned <code>Timestamp</code> + * @return a new <code>java.sql.Timestamp</code> with the parameter value. + * A <code>null</code> reference is returned for an SQL value of + * <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(String parameterName, Calendar cal) + throws SQLException; + + /** + * Gets the value of a specified JDBC DATALINK parameter as a java.net.URL. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @return a java.sql.Datalink with the parameter value. null if the value + * is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public URL getURL(int parameterIndex) throws SQLException; + + /** + * Returns the named parameter's JDBC <code>DATALINK</code> value in a new + * Java <code>java.net.URL</code>. + * + * @param parameterName + * the parameter name + * @return a new <code>java.net.URL</code> encapsulating the parameter + * value. A <code>null</code> reference is returned for an SQL + * value of <code>NULL</code> + * @throws SQLException + * if a database error happens + */ + public URL getURL(String parameterName) throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. All OUT parameters must + * have their Type defined before a stored procedure is executed. + * <p> + * The Type defined by this method fixes the Java type that must be + * retrieved using the getter methods of CallableStatement. If a database + * specific type is expected for a parameter, the Type java.sql.Types.OTHER + * should be used. Note that there is another variant of this method for + * User Defined Types or a REF type. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param sqlType + * the JDBC type as defined by java.sql.Types. The JDBC types + * NUMERIC and DECIMAL should be defined using the version of + * <code>registerOutParameter</code> that takes a + * <code>scale</code> parameter. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(int parameterIndex, int sqlType) + throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. All OUT parameters must + * have their Type defined before a stored procedure is executed. This + * version of the registerOutParameter method, which has a scale parameter, + * should be used for the JDBC types NUMERIC and DECIMAL, where there is a + * need to specify the number of digits expected after the decimal point. + * <p> + * The Type defined by this method fixes the Java type that must be + * retrieved using the getter methods of CallableStatement. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param sqlType + * the JDBC type as defined by java.sql.Types. + * @param scale + * the number of digits after the decimal point. Must be greater + * than or equal to 0. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(int parameterIndex, int sqlType, int scale) + throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. This variant of the method + * is designed for use with parameters that are User Defined Types (UDT) or + * a REF type, although it can be used for any type. + * + * @param paramIndex + * the parameter number index, where the first parameter has + * index 1 + * @param sqlType + * a JDBC type expressed as a constant from {@link Types} + * @param typeName + * an SQL type name. For a REF type, this name should be the + * fully qualified name of the referenced type. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(int paramIndex, int sqlType, + String typeName) throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. All OUT parameters must + * have their Type defined before a stored procedure is executed. + * <p> + * The Type defined by this method fixes the Java type that must be + * retrieved using the getter methods of CallableStatement. If a database + * specific type is expected for a parameter, the Type java.sql.Types.OTHER + * should be used. Note that there is another variant of this method for + * User Defined Types or a REF type. + * + * @param parameterName + * the parameter name + * @param sqlType + * a JDBC type expressed as a constant from {@link Types}. Types + * NUMERIC and DECIMAL should be defined using the variant of + * this method that takes a <code>scale</code> parameter. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(String parameterName, int sqlType) + throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. All OUT parameters must + * have their Type defined before a stored procedure is executed. This + * version of the registerOutParameter method, which has a scale parameter, + * should be used for the JDBC types NUMERIC and DECIMAL, where there is a + * need to specify the number of digits expected after the decimal point. + * <p> + * The Type defined by this method fixes the Java type that must be + * retrieved using the getter methods of CallableStatement. + * + * @param parameterName + * the parameter name + * @param sqlType + * a JDBC type expressed as a constant from {@link Types} + * @param scale + * the number of digits after the decimal point. Must be greater + * than or equal to 0. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(String parameterName, int sqlType, + int scale) throws SQLException; + + /** + * Defines the Type of a specified OUT parameter. This variant of the method + * is designed for use with parameters that are User Defined Types (UDT) or + * a REF type, although it can be used for any type.Registers the designated + * output parameter. + * + * @param parameterName + * the parameter name + * @param sqlType + * a JDBC type expressed as a constant from {@link Types} + * @param typeName + * the fully qualified name of an SQL structured type. For a REF + * type, this name should be the fully qualified name of the + * referenced type. + * @throws SQLException + * if a database error happens + */ + public void registerOutParameter(String parameterName, int sqlType, + String typeName) throws SQLException; + + /** + * Sets the value of a specified parameter to the content of a supplied + * InputStream, which has a specified number of bytes. + * <p> + * This is a good method for setting an SQL LONVARCHAR parameter where the + * length of the data is large. Data is read from the InputStream until + * end-of-file is reached or the specified number of bytes is copied. + * + * @param parameterName + * the parameter name + * @param theInputStream + * the ASCII InputStream carrying the data to update the + * parameter with + * @param length + * the number of bytes in the InputStream to copy to the + * parameter + * @throws SQLException + * if a database error happens + */ + public void setAsciiStream(String parameterName, + InputStream theInputStream, int length) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied + * java.math.BigDecimal value. + * + * @param parameterName + * the name of the parameter + * @param theBigDecimal + * the java.math.BigInteger value to set + * @throws SQLException + * if a database error happens + */ + public void setBigDecimal(String parameterName, BigDecimal theBigDecimal) + throws SQLException; + + /** + * Sets the value of a specified parameter to the content of a supplied + * binary InputStream, which has a specified number of bytes. + * <p> + * Use this method when a large amount of data needs to be set into a + * LONGVARBINARY parameter. + * + * @param parameterName + * the name of the parameter + * @param theInputStream + * the binary InputStream carrying the data to update the + * parameter + * @param length + * the number of bytes in the InputStream to copy to the + * parameter + * @throws SQLException + * if a database error happens + */ + public void setBinaryStream(String parameterName, + InputStream theInputStream, int length) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied boolean value. + * + * @param parameterName + * the parameter name + * @param theBoolean + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setBoolean(String parameterName, boolean theBoolean) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied byte value. + * + * @param parameterName + * the parameter name + * @param theByte + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setByte(String parameterName, byte theByte) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied array of bytes. The + * array is mapped to <code>VARBINARY</code> or else + * <code>LONGVARBINARY</code> in the connected database. + * + * @param parameterName + * the parameter name + * @param theBytes + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setBytes(String parameterName, byte[] theBytes) + throws SQLException; + + /** + * Sets the value of a specified parameter to the character content of a + * Reader object, with the specified length of character data. + * + * @param parameterName + * the parameter name + * @param reader + * the new value with which to update the parameter + * @param length + * a count of the characters contained in <code>reader</code> + * @throws SQLException + * if a database error happens + */ + public void setCharacterStream(String parameterName, Reader reader, + int length) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Date + * value. + * + * @param parameterName + * the parameter name + * @param theDate + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setDate(String parameterName, Date theDate) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Date + * value, using a supplied Calendar to map the Date. The Calendar allows the + * application to control the timezone used to compute the SQL DATE in the + * database - without the supplied Calendar, the driver uses the default + * timezone of the Java virtual machine. + * + * @param parameterName + * the parameter name + * @param theDate + * the new value with which to update the parameter + * @param cal + * a Calendar to use to construct the SQL DATE value + * @throws SQLException + * if a database error happens + */ + public void setDate(String parameterName, Date theDate, Calendar cal) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied double value. + * + * @param parameterName + * the parameter name + * @param theDouble + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setDouble(String parameterName, double theDouble) + throws SQLException; + + /** + * Sets the value of a specified parameter to to a supplied float value. + * + * @param parameterName + * the parameter name + * @param theFloat + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setFloat(String parameterName, float theFloat) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied int value. + * + * @param parameterName + * the parameter name + * @param theInt + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setInt(String parameterName, int theInt) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied long value. + * + * @param parameterName + * the parameter name + * @param theLong + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setLong(String parameterName, long theLong) throws SQLException; + + /** + * Sets the value of a specified parameter to SQL NULL. Don't use this + * version of setNull for User Defined Types or for REF type parameters. + * + * @param parameterName + * the parameter name + * @param sqlType + * a JDBC type expressed as a constant from {@link Types} + * @throws SQLException + * if a database error happens + */ + public void setNull(String parameterName, int sqlType) throws SQLException; + + /** + * Sets the value of a specified parameter to be SQL NULL where the + * parameter type is either <code>REF</code> or user defined (e.g. + * <code>STRUCT</code>, <code>JAVA_OBJECT</code> etc). + * <p> + * For reasons of portability, the caller is expected to supply both the SQL + * Type code and Type name (which is just the parameter name if the type is + * user defined, or the name of the type being referenced if a REF). + * + * @param parameterName + * the parameter name + * @param sqlType + * a JDBC type expressed as a constant from {@link Types} + * @param typeName + * if the target parameter is a user defined type then this + * should contain the full type name + * + * the fully qualified name of a UDT or REF type - ignored if the parameter + * is not a UDT. + * @throws SQLException + * if a database error happens + */ + public void setNull(String parameterName, int sqlType, String typeName) + throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. Prior to + * issuing this request to the connected database <code>theObject</code> + * is transformed to the corresponding SQL type according to the normal Java + * to SQL mapping rules. + * <p> + * If the object's class implements the interface SQLData, the JDBC driver + * calls <code>SQLData.writeSQL</code> to write it to the SQL data stream. + * If <code>theObject</code> implements any of the following interfaces + * then it is the role of the driver to flow the value to the connected + * database using the appropriate SQL type : + * <ul> + * <li>{@link Ref} + * <li>{@link Struct} + * <li>{@link Array} + * <li>{@link Clob} + * <li>{@link Blob} + * </ul> + * + * @param parameterName + * the parameter name + * @param theObject + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setObject(String parameterName, Object theObject) + throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. + * <p> + * The Object is converted to the given targetSqlType before it is sent to + * the database. If the object has a custom mapping (its class implements + * the interface SQLData), the JDBC driver will call the method + * SQLData.writeSQL to write it to the SQL data stream. If + * <code>theObject</code> implements any of the following interfaces then + * it is the role of the driver to flow the value to the connected database + * using the appropriate SQL type : + * <ul> + * <li>{@link Ref} + * <li>{@link Struct} + * <li>{@link Array} + * <li>{@link Clob} + * <li>{@link Blob} + * </ul> + * + * @param parameterName + * the parameter name + * @param theObject + * the new value with which to update the parameter + * @param targetSqlType + * a JDBC type expressed as a constant from {@link Types} + * @throws SQLException + * if a database error happens + */ + public void setObject(String parameterName, Object theObject, + int targetSqlType) throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. + * <p> + * The Object is converted to the given targetSqlType before it is sent to + * the database. If the object has a custom mapping (its class implements + * the interface SQLData), the JDBC driver will call the method + * SQLData.writeSQL to write it to the SQL data stream. If + * <code>theObject</code> implements any of the following interfaces then + * it is the role of the driver to flow the value to the connected database + * using the appropriate SQL type : + * <ul> + * <li>{@link Ref} + * <li>{@link Struct} + * <li>{@link Array} + * <li>{@link Clob} + * <li>{@link Blob} + * </ul> + * + * @param parameterName + * the parameter name + * @param theObject + * the new value with which to update the parameter + * @param targetSqlType + * a JDBC type expressed as a constant from {@link Types} + * @param scale + * where applicable, the number of digits after the decimal + * point. + * @throws SQLException + * if a database error happens + */ + public void setObject(String parameterName, Object theObject, + int targetSqlType, int scale) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied short value. + * + * @param parameterName + * the name of the parameter + * @param theShort + * a short value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setShort(String parameterName, short theShort) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied String. + * + * @param parameterName + * the name of the parameter + * @param theString + * a String value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setString(String parameterName, String theString) + throws SQLException; + + /** + * Sets the value of the parameter named <code>parameterName</code> to the + * value of the supplied <code>java.sql.Time</code>. + * + * @param parameterName + * the parameter name + * @param theTime + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setTime(String parameterName, Time theTime) throws SQLException; + + /** + * Sets the value of the parameter named <code>parameterName</code> to the + * value of the supplied <code>java.sql.Time</code> using the supplied + * Calendar. + * <p> + * The driver uses the supplied Calendar to create the SQL TIME value, which + * allows it to use a custom timezone - otherwise the driver uses the + * default timezone of the Java virtual machine. + * + * @param parameterName + * the parameter name + * @param theTime + * the new value with which to update the parameter + * @param cal + * used for creating the new SQL <code>TIME</code> value + * @throws SQLException + * if a database error happens + */ + public void setTime(String parameterName, Time theTime, Calendar cal) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Timestamp + * value. + * + * @param parameterName + * the parameter name + * @param theTimestamp + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setTimestamp(String parameterName, Timestamp theTimestamp) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Timestamp + * value, using the supplied Calendar. + * <p> + * The driver uses the supplied Calendar to create the SQL TIMESTAMP value, + * which allows it to use a custom timezone - otherwise the driver uses the + * default timezone of the Java virtual machine. + * + * @param parameterName + * the parameter name + * @param theTimestamp + * the new value with which to update the parameter + * @param cal + * used for creating the new SQL <code>TIME</code> value + * @throws SQLException + * if a database error happens + */ + public void setTimestamp(String parameterName, Timestamp theTimestamp, + Calendar cal) throws SQLException; + + /** + * Sets the value of a specified parameter to the supplied java.net.URL. + * + * @param parameterName + * the parameter name + * @param theURL + * the new value with which to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setURL(String parameterName, URL theURL) throws SQLException; + + /** + * Gets whether the value of the last OUT parameter read was SQL NULL. + * + * @return true if the last parameter was SQL NULL, false otherwise. + * @throws SQLException + * if a database error happens + */ + public boolean wasNull() throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Clob.java b/sql/src/main/java/java/sql/Clob.java new file mode 100644 index 0000000..e97b3b1 --- /dev/null +++ b/sql/src/main/java/java/sql/Clob.java @@ -0,0 +1,174 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.io.OutputStream; +import java.io.Writer; + +/** + * A Java interface mapping for the SQL CLOB type. + * <p> + * An SQL CLOB type stores a large array of characters as the value in a column + * of a database. + * <p> + * The java.sql.Clob interface provides methods for setting and retrieving data + * in the Clob, for querying Clob data length, for searching for data within the + * Clob. + */ +public interface Clob { + + /** + * Gets the value of this Clob object as an ASCII stream. + * + * @return an ASCII InputStream giving access to the Clob data + * @throws SQLException + * if an error occurs accessing the Clob + */ + public InputStream getAsciiStream() throws SQLException; + + /** + * Gets the value of this Clob object as a java.io.Reader. + * + * @return a character stream Reader object giving access to the Clob data + * @throws SQLException + * if an error occurs accessing the Clob + */ + public Reader getCharacterStream() throws SQLException; + + /** + * Gets a copy of a specified substring in this Clob. + * + * @param pos + * the index of the start of the substring in the Clob + * @param length + * the length of the data to retrieve + * @return A String containing the requested data + * @throws SQLException + * if an error occurs accessing the Clob + */ + public String getSubString(long pos, int length) throws SQLException; + + /** + * Retrieves the number of characters in this Clob object. + * + * @return a long value with the number of character in this Clob. + * @throws SQLException + * if an error occurs accessing the Clob + */ + public long length() throws SQLException; + + /** + * Retrieves the character position at which a specified Clob object appears + * in this Clob object. + * + * @param searchstr + * the specified Clob to search for + * @param start + * the position within this Clob to start the search + * @return a long value with the position at which the specified Clob occurs + * within this Clob. + * @throws SQLException + * if an error occurs accessing the Clob + */ + public long position(Clob searchstr, long start) throws SQLException; + + /** + * Retrieves the character position at which a specified substring appears + * in this Clob object. + * + * @param searchstr + * th String to search for + * @param start + * the position at which to start the search within this Clob. + * @return a long value with the position at which the specified String + * occurs within this Clob. + * @throws SQLException + * if an error occurs accessing the Clob + */ + public long position(String searchstr, long start) throws SQLException; + + /** + * Retrieves a stream which can be used to write Ascii characters to this + * Clob object, starting at specified position. + * + * @param pos + * the position at which to start the writing + * @return an OutputStream which can be used to write ASCII characters to + * this Clob. + * @throws SQLException + * if an error occurs accessing the Clob + */ + public OutputStream setAsciiStream(long pos) throws SQLException; + + /** + * Retrieves a stream which can be used to write a stream of Unicode + * characters to this Clob object, at a specified position. + * + * @param pos + * the position at which to start the writing + * @return a Writer which can be used to write Unicode characters to this + * Clob. + * @throws SQLException + * if an error occurs accessing the Clob + */ + public Writer setCharacterStream(long pos) throws SQLException; + + /** + * Writes a given Java String to this Clob object at a specified position. + * + * @param pos + * the position at which to start the writing + * @param str + * the String to write + * @return the number of characters written + * @throws SQLException + * if an error occurs accessing the Clob + */ + public int setString(long pos, String str) throws SQLException; + + /** + * Writes len characters of String, starting at a specified character + * offset, to this Clob. + * + * @param pos + * the position at which to start the writing + * @param str + * the String to write + * @param offset + * the offset within str to start writing from + * @param len + * the number of characters to write + * @return the number of characters written + * @throws SQLException + * if an error occurs accessing the Clob + */ + public int setString(long pos, String str, int offset, int len) + throws SQLException; + + /** + * Truncates this Clob to have a specified length of characters. + * + * @param len + * the length in characters to truncate this Clob + * @throws SQLException + * if an error occurs accessing the Clob + */ + public void truncate(long len) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Connection.java b/sql/src/main/java/java/sql/Connection.java new file mode 100644 index 0000000..4683299 --- /dev/null +++ b/sql/src/main/java/java/sql/Connection.java @@ -0,0 +1,759 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Map; + +/** + * A Connection represents a link from a Java application to a database. All SQL + * statements and results are returned within the context of a connection. + * + */ +public interface Connection { + + /** + * A constant indicating that transactions are not supported. + */ + public static final int TRANSACTION_NONE = 0; + + /** + * No dirty reads are permitted. Transactions may not read a row containing + * changes that have not yet been committed. + */ + public static final int TRANSACTION_READ_COMMITTED = 2; + + /** + * Dirty reads (reading from table rows containing changes that have not yet + * been committed), non-repeatable reads (reading table rows more than once + * in a transaction but getting back different data because other + * transactions may have altered rows between reads), and phantom reads + * (retrieving additional "phantom" rows in the course of repeated table + * reads because other transactions may have inserted additional rows that + * satisfy an SQL <code>WHERE</code> clause) are <b>all permitted</b>. + */ + public static final int TRANSACTION_READ_UNCOMMITTED = 1; + + /** + * A constant indicating that dirty reads and non-repeatable reads are + * prevented; phantom reads can occur. + */ + public static final int TRANSACTION_REPEATABLE_READ = 4; + + /** + * Dirty reads (reading from table rows containing changes that have not yet + * been committed), non-repeatable reads (reading table rows more than once + * in a transaction but getting back different data because other + * transactions may have altered rows between reads), and phantom reads + * (retrieving additional "phantom" rows in the course of repeated table + * reads because other transactions may have inserted additional rows that + * satisfy an SQL <code>WHERE</code> clause) are <b>all prevented</b>. + */ + public static final int TRANSACTION_SERIALIZABLE = 8; + + /** + * Throws away any warnings that may have arisen for this connection. + * Subsequent calls to {@link #getWarnings()} will return <code>null</code> + * up until a brand new warning condition occurs. + * + * @throws SQLException + * if there is a problem accessing the database + */ + public void clearWarnings() throws SQLException; + + /** + * Causes the instant release of all database and driver connection + * resources associated with this object. Any subsequent invocations of this + * method will have no effect. + * <p> + * It is strongly recommended that all Connections are closed before they + * are dereferenced by the application ready for garbage collection. While + * the finalize method of the Connection will close the Connection before + * garbage collection takes place, it is not advisable to leave the close + * operation to take place in this way. Unpredictable performance may result + * from closing Connections in the finalizer. + * + * @throws SQLException + * if there is a problem accessing the database + */ + public void close() throws SQLException; + + /** + * Commits all of the changes made subsequent to the last commit or rollback + * of the associated transaction. All locks in the database held by this + * connection are also relinquished. Calling this operation on connection + * objects in auto-commit mode is an error. + * + * @throws SQLException + * if there is a problem accessing the database or if the target + * connection instance is in auto-commit mode. + */ + public void commit() throws SQLException; + + /** + * Returns a new instance of <code>Statement</code> for issuing SQL + * commands to the remote database. + * <p> + * ResultSets generated by the returned Statement will default to type + * <code>TYPE_FORWARD_ONLY</code> and concurrency level + * <code>CONCUR_READ_ONLY</code>. + * + * @return a <code>Statement</code> object with default settings. + * @throws SQLException + * if there is a problem accessing the database + */ + public Statement createStatement() throws SQLException; + + /** + * Returns a new instance of <code>Statement</code> whose associated + * <code>ResultSet</code>s will have the characteristics specified in the + * type, concurrency and holdability arguments. + * + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * </ul> + * @return a new instance of <code>Statement</code> capable of + * manufacturing <code>ResultSet</code>s that satisfy the + * specified <code>resultSetType</code> and + * <code>resultSetConcurrency</code> values. + * @throws SQLException + * if there is a problem accessing the database + */ + public Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException; + + /** + * Returns a new instance of <code>Statement</code> whose associated + * <code>ResultSet</code>s will have the characteristics specified in the + * type, concurrency and holdability arguments. + * + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * </ul> + * @param resultSetHoldability + * one of : + * <ul> + * <li>{@link ResultSet#HOLD_CURSORS_OVER_COMMIT} + * <li>{@link ResultSet#CLOSE_CURSORS_AT_COMMIT} + * </ul> + * @return a new instance of <code>Statement</code> capable of + * manufacturing <code>ResultSet</code>s that satisfy the + * specified <code>resultSetType</code>, + * <code>resultSetConcurrency</code> and + * <code>resultSetHoldability</code> values. + * @throws SQLException + * if there is a problem accessing the database + */ + public Statement createStatement(int resultSetType, + int resultSetConcurrency, int resultSetHoldability) + throws SQLException; + + /** + * Returns a boolean indication of whether or not this connection is in the + * auto-commit operating mode. + * + * @return <code>true</code> if auto-commit is on, otherwise + * <code>false</code> + * @throws SQLException + * if there is a problem accessing the database + */ + public boolean getAutoCommit() throws SQLException; + + /** + * Gets this Connection object's current catalog name. + * + * @return the catalog name. <code>null</code> if there is no catalog + * name. + * @throws SQLException + * if there is a problem accessing the database + */ + public String getCatalog() throws SQLException; + + /** + * Returns the kind of holdability that any <code>ResultSet</code>s made + * from this instance will have. + * + * @return one of : + * <ul> + * <li>{@link ResultSet#HOLD_CURSORS_OVER_COMMIT} + * <li>{@link ResultSet#CLOSE_CURSORS_AT_COMMIT} + * </ul> + * @throws SQLException + * if there is a problem accessing the a database + */ + public int getHoldability() throws SQLException; + + /** + * Gets the metadata about the database referenced by this connection. The + * returned <code>DatabaseMetaData</code> describes the database + * topography, available stored procedures, SQL syntax and so on. + * + * @return a <code>DatabaseMetaData</code> object containing the database + * description + * @throws SQLException + * if there is a problem accessing the a database + */ + public DatabaseMetaData getMetaData() throws SQLException; + + /** + * Returns the present value of transaction isolation for this Connection + * instance. + * + * @return the transaction isolation value + * @throws SQLException + * if there is a problem accessing the database + * @see #TRANSACTION_NONE + * @see #TRANSACTION_READ_COMMITTED + * @see #TRANSACTION_READ_UNCOMMITTED + * @see #TRANSACTION_REPEATABLE_READ + * @see #TRANSACTION_SERIALIZABLE + */ + public int getTransactionIsolation() throws SQLException; + + /** + * Returns the Type Map associated with this Connection object. The type map + * will be empty unless the application has added at least one entry. + * + * @return the Type Map as a <code>java.util.Map</code> + * @throws SQLException + * if there is a problem accessing the database + */ + public Map<String, Class<?>> getTypeMap() throws SQLException; + + /** + * Gets the first instance of any <code>SQLWarning</code> objects that may + * have been created in the use of this connection. If at least one warning + * has occurred then this operation returns the first one reported. A + * <code>null</code> indicates that no warnings have occurred. + * <p> + * By invoking the {@link SQLWarning#getNextWarning()} method of the + * returned <code>SQLWarning</code> object it is possible to obtain all + * warning objects. + * + * @return the first warning as an SQLWarning object (may be + * <code>null</code>) + * @throws SQLException + * if there is a problem accessing the database or if the call + * has been made on a connection which has been previously + * closed. + */ + public SQLWarning getWarnings() throws SQLException; + + /** + * Returns a boolean indication of whether or not this connection is in the + * closed state. The closed state may be entered into as a consequence of a + * successful invocation of the {@link #close()} method or else if an error + * has occurred that prevents the connection from functioning normally. + * + * @return <code>true</code> if closed, otherwise <code>false</code> + * @throws SQLException + * if there is a problem accessing the database + */ + public boolean isClosed() throws SQLException; + + /** + * Returns a boolean indication of whether or not this connection is + * currently in read-only state. + * + * @return <code>true</code> if in read-only state, otherwise + * <code>false</code>. + * @throws SQLException + * if there is a problem accessing the database + */ + public boolean isReadOnly() throws SQLException; + + /** + * Returns a string representation of the input SQL statement + * <code>sql</code> expressed in the underlying system's native SQL + * syntax. + * + * @param sql + * the JDBC form of an SQL statement. + * @return the SQL statement in native database format. + * @throws SQLException + * if there is a problem accessing the database + */ + public String nativeSQL(String sql) throws SQLException; + + /** + * Returns a new instance of <code>CallableStatement</code> that may be + * used for making stored procedure calls to the database. + * + * @param sql + * the SQL statement that calls the stored function + * @return a new instance of <code>CallableStatement</code> representing + * the SQL statement. <code>ResultSet</code>s emitted from this + * <code>CallableStatement</code> will default to type + * {@link ResultSet#TYPE_FORWARD_ONLY} and concurrency + * {@link ResultSet#CONCUR_READ_ONLY}. + * @throws SQLException + * if a problem occurs accessing the database + */ + public CallableStatement prepareCall(String sql) throws SQLException; + + /** + * Returns a new instance of <code>CallableStatement</code> that may be + * used for making stored procedure calls to the database. + * <code>ResultSet</code>s emitted from this + * <code>CallableStatement</code> will satisfy the specified + * <code>resultSetType</code> and <code>resultSetConcurrency</code> + * values. + * + * @param sql + * the SQL statement + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * </ul> + * @return a new instance of <code>CallableStatement</code> representing + * the precompiled SQL statement. <code>ResultSet</code>s emitted + * from this <code>CallableStatement</code> will satisfy the + * specified <code>resultSetType</code> and + * <code>resultSetConcurrency</code> values. + * @throws SQLException + * if a problem occurs accessing the database + */ + public CallableStatement prepareCall(String sql, int resultSetType, + int resultSetConcurrency) throws SQLException; + + /** + * Returns a new instance of <code>CallableStatement</code> that may be + * used for making stored procedure calls to the database. ResultSets + * created from this <code>CallableStatement</code> will have + * characteristics determined by the specified type, concurrency and + * holdability arguments. + * + * @param sql + * the SQL statement + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * </ul> + * @param resultSetHoldability + * one of : + * <ul> + * <li>{@link ResultSet#HOLD_CURSORS_OVER_COMMIT} + * <li>{@link ResultSet#CLOSE_CURSORS_AT_COMMIT} + * </ul> + * @return a new instance of <code>CallableStatement</code> representing + * the precompiled SQL statement. <code>ResultSet</code>s emitted + * from this <code>CallableStatement</code> will satisfy the + * specified <code>resultSetType</code>, + * <code>resultSetConcurrency</code> and + * <code>resultSetHoldability</code> values. + * @throws SQLException + * if a problem occurs accessing the database + */ + public CallableStatement prepareCall(String sql, int resultSetType, + int resultSetConcurrency, int resultSetHoldability) + throws SQLException; + + /** + * Returns a new instance of <code>PreparedStatement</code> that may be + * used any number of times to execute parameterized requests on the + * database server. + * <p> + * Subject to JDBC driver support, this operation will attempt to send the + * precompiled version of the statement to the database. Alternatively, if + * the driver is not capable of flowing precompiled statements, the + * statement will not reach the database server until it is executed. This + * will have a bearing on precisely when <code>SQLException</code> + * instances get raised. + * <p> + * By default, ResultSets from the returned object will be + * {@link ResultSet#TYPE_FORWARD_ONLY} type with a + * {@link ResultSet#CONCUR_READ_ONLY} mode of concurrency. + * + * @param sql + * the SQL statement. + * @return the PreparedStatement containing the supplied SQL statement + * @throws SQLException + * if there is a problem accessing the database + */ + public PreparedStatement prepareStatement(String sql) throws SQLException; + + /** + * Creates a default PreparedStatement that can retrieve automatically + * generated keys. Parameter <code>autoGeneratedKeys</code> may be used to + * specify to the driver if such keys should be made accessible. This is + * only the case when <code>sql</code> is an insert statement. + * <p> + * An SQL statement which may have IN parameters can be stored and + * precompiled in a PreparedStatement. The PreparedStatement can then be + * used to execute the statement multiple times in an efficient way. + * <p> + * Subject to JDBC driver support, this operation will attempt to send the + * precompiled version of the statement to the database. Alternatively, if + * the driver is not capable of flowing precompiled statements, the + * statement will not reach the database server until it is executed. This + * will have a bearing on precisely when <code>SQLException</code> + * instances get raised. + * <p> + * By default, ResultSets from the returned object will be + * {@link ResultSet#TYPE_FORWARD_ONLY} type with a + * {@link ResultSet#CONCUR_READ_ONLY} mode of concurrency. + * + * @param sql + * the SQL statement. + * @param autoGeneratedKeys + * one of : + * <ul> + * <li>{@link Statement#RETURN_GENERATED_KEYS} + * <li>{@link Statement#NO_GENERATED_KEYS} + * </ul> + * @return a new <code>PreparedStatement</code> instance representing the + * input SQL statement. + * @throws SQLException + * if there is a problem accessing the database + */ + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * Creates a default PreparedStatement that can retrieve the auto-generated + * keys designated by a supplied array. If <code>sql</code> is an SQL + * <code>INSERT</code> statement, parameter <code>columnIndexes</code> + * is expected to hold the index values for each column in the statement's + * intended database table containing the autogenerated-keys of interest. + * Otherwise <code>columnIndexes</code> is ignored. + * <p> + * Subject to JDBC driver support, this operation will attempt to send the + * precompiled version of the statement to the database. Alternatively, if + * the driver is not capable of flowing precompiled statements, the + * statement will not reach the database server until it is executed. This + * will have a bearing on precisely when <code>SQLException</code> + * instances get raised. + * <p> + * By default, ResultSets from the returned object will be + * {@link ResultSet#TYPE_FORWARD_ONLY} type with a + * {@link ResultSet#CONCUR_READ_ONLY} mode of concurrency. + * + * @param sql + * the SQL statement. + * @param columnIndexes + * the indexes of the columns for which auto-generated keys + * should be made available. + * @return the PreparedStatement containing the supplied SQL statement + * @throws SQLException + * if a problem occurs accessing the database + */ + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) + throws SQLException; + + /** + * Creates a PreparedStatement that generates ResultSets with the specified + * values of <code>resultSetType</code> and + * <code>resultSetConcurrency</code>. + * + * @param sql + * the SQL statement. It can contain one or more '?' IN parameter + * placeholders + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * </ul> + * @return a new instance of <code>PreparedStatement</code> containing the + * SQL statement <code>sql</code>. <code>ResultSet</code>s + * emitted from this <code>PreparedStatement</code> will satisfy + * the specified <code>resultSetType</code> and + * <code>resultSetConcurrency</code> values. + * @throws SQLException + * if a problem occurs accessing the database + */ + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency) throws SQLException; + + /** + * Creates a PreparedStatement that generates ResultSets with the specified + * type, concurrency and holdability + * + * @param sql + * the SQL statement. It can contain one or more '?' IN parameter + * placeholders + * @param resultSetType + * one of : + * <ul> + * <li>{@link ResultSet#TYPE_SCROLL_SENSITIVE} + * <li>{@link ResultSet#TYPE_SCROLL_INSENSITIVE} + * <li>{@link ResultSet#TYPE_FORWARD_ONLY} + * </ul> + * @param resultSetConcurrency + * one of : + * <ul> + * <li>{@link ResultSet#CONCUR_READ_ONLY} + * <li>{@link ResultSet#CONCUR_UPDATABLE} + * </ul> + * @param resultSetHoldability + * one of : + * <ul> + * <li>{@link ResultSet#HOLD_CURSORS_OVER_COMMIT} + * <li>{@link ResultSet#CLOSE_CURSORS_AT_COMMIT} + * </ul> + * + * @return a new instance of <code>PreparedStatement</code> containing the + * SQL statement <code>sql</code>. <code>ResultSet</code>s + * emitted from this <code>PreparedStatement</code> will satisfy + * the specified <code>resultSetType</code>, + * <code>resultSetConcurrency</code> and + * <code>resultSetHoldability</code> values. + * @throws SQLException + * if a problem occurs accessing the database + */ + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency, int resultSetHoldability) + throws SQLException; + + /** + * Creates a default PreparedStatement that can retrieve the auto-generated + * keys designated by a supplied array. If <code>sql</code> is an SQL + * <code>INSERT</code> statement, <code>columnNames</code> is expected + * to hold the names of each column in the statement's associated database + * table containing the autogenerated-keys of interest. Otherwise + * <code>columnNames</code> is ignored. + * <p> + * Subject to JDBC driver support, this operation will attempt to send the + * precompiled version of the statement to the database. Alternatively, if + * the driver is not capable of flowing precompiled statements, the + * statement will not reach the database server until it is executed. This + * will have a bearing on precisely when <code>SQLException</code> + * instances get raised. + * <p> + * By default, ResultSets from the returned object will be + * {@link ResultSet#TYPE_FORWARD_ONLY} type with a + * {@link ResultSet#CONCUR_READ_ONLY} mode of concurrency. + * + * @param sql + * the SQL statement. + * @param columnNames + * the names of the columns for which auto-generated keys should + * be made available. + * @return the PreparedStatement containing the supplied SQL statement + * @throws SQLException + * if a problem occurs accessing the database + */ + public PreparedStatement prepareStatement(String sql, String[] columnNames) + throws SQLException; + + /** + * Releases <code>savepoint</code> from the present transaction. Once + * removed, the <code>Savepoint</code> is considered invalid and should + * not be referenced further. + * + * @param savepoint + * the object targeted for removal + * @throws SQLException + * if there is a problem with accessing the database or if + * <code>savepoint</code> is considered not valid in this + * transaction. + */ + public void releaseSavepoint(Savepoint savepoint) throws SQLException; + + /** + * Rolls back all updates made so far in this transaction as well as + * relinquishing all acquired database locks. It is an error to invoke this + * operation when in auto-commit mode. + * + * @throws SQLException + * if there is a problem with the database or if the method is + * called while in auto-commit mode of operation. + */ + public void rollback() throws SQLException; + + /** + * Undoes all changes made after the supplied Savepoint object was set. This + * method should only be used when auto-commit mode is disabled. + * + * @param savepoint + * the Savepoint to roll back to + * @throws SQLException + * if there is a problem accessing the database + */ + public void rollback(Savepoint savepoint) throws SQLException; + + /** + * Sets this connection's auto-commit mode on or off. + * <p> + * Putting a Connection into auto-commit mode means that all associated SQL + * statements will be run and committed in their own separate transactions. + * Alternatively, auto-commit set to off means that associated SQL + * statements get grouped into transactions that need to be completed by + * explicit calls to either the {@link #commit()} or {@link #rollback()} + * methods. + * <p> + * Auto-commit is the default mode for new connection instances. + * <p> + * When in this mode, commits will automatically occur upon successful SQL + * statement completion or upon successful completion of an execute. + * Statements are not considered successfully complete until all associated + * <code>ResultSet</code>s and output parameters have been obtained or + * closed. + * <p> + * Calling this operation during an uncommitted transaction will result in + * it being committed. + * + * @param autoCommit + * boolean indication of whether to put the target connection + * into auto-commit mode (<code>true</code>) or not (<code>false</code>) + * + * @throws SQLException + * if there is a problem accessing the database + */ + public void setAutoCommit(boolean autoCommit) throws SQLException; + + /** + * Sets the catalog name for this connection. This is used to select a + * subspace of the database for future work. If the driver does not support + * catalog names, this method is ignored. + * + * @param catalog + * the catalog name to use. + * @throws SQLException + * if there is a problem accessing the database + */ + public void setCatalog(String catalog) throws SQLException; + + /** + * Sets the holdability of ResultSets created by this Connection. + * + * @param holdability + * one of : + * <ul> + * <li>{@link ResultSet#CLOSE_CURSORS_AT_COMMIT} + * <li>{@link ResultSet#HOLD_CURSORS_OVER_COMMIT} + * <li> + * </ul> + * @throws SQLException + * if there is a problem accessing the database + */ + public void setHoldability(int holdability) throws SQLException; + + /** + * Sets this connection to read-only mode. + * <p> + * This serves as a hint to the driver, which can enable database + * optimizations. + * + * @param readOnly + * true to set the Connection to read only mode. false disables + * read-only mode + * @throws SQLException + * if there is a problem accessing the database + */ + public void setReadOnly(boolean readOnly) throws SQLException; + + /** + * Creates an unnamed Savepoint in the current transaction. + * + * @return a Savepoint object for this savepoint. + * @throws SQLException + * if there is a problem accessing the database + */ + public Savepoint setSavepoint() throws SQLException; + + /** + * Creates a named Savepoint in the current transaction. + * + * @param name + * the name to use for the new Savepoint. + * @return a Savepoint object for this savepoint. + * @throws SQLException + * if there is a problem accessing the database + */ + public Savepoint setSavepoint(String name) throws SQLException; + + /** + * Sets the transaction isolation level for this Connection. + * <p> + * If this method is called during a transaction, the results are + * implementation defined. + * + * @param level + * the new transaction isolation level to use from the following + * list of possible values : + * <ul> + * <li>{@link #TRANSACTION_READ_COMMITTED} + * <li>{@link #TRANSACTION_READ_UNCOMMITTED} + * <li>{@link #TRANSACTION_REPEATABLE_READ} + * <li>{@link #TRANSACTION_SERIALIZABLE} + * </ul> + * @throws SQLException + * if there is a problem with the database or if the value of + * <code>level</code> is not one of the expected constant + * values. + */ + public void setTransactionIsolation(int level) throws SQLException; + + /** + * Sets the <code>TypeMap</code> for this connection. The input + * <code>map</code> should contain mappings between complex Java and SQL + * types. + * + * @param map + * the new type map + * @throws SQLException + * if there is a problem accessing the database or if + * <code>map</code> is not an instance of {@link Map}. + */ + public void setTypeMap(Map<String, Class<?>> map) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/DataTruncation.java b/sql/src/main/java/java/sql/DataTruncation.java new file mode 100644 index 0000000..7150ec7 --- /dev/null +++ b/sql/src/main/java/java/sql/DataTruncation.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.Serializable; + +/** + * An exception which is thrown when a JDBC driver unexpectedly truncates a data + * value either when reading or when writing data. + * + * The SQLState value for a <code>DataTruncation</code> is <code>01004</code>. + */ +public class DataTruncation extends SQLWarning implements Serializable { + + private static final long serialVersionUID = 6464298989504059473L; + + private int index = 0; + + private boolean parameter = false; + + private boolean read = false; + + private int dataSize = 0; + + private int transferSize = 0; + + private static final String THE_REASON = "Data truncation"; //$NON-NLS-1$ + + private static final String THE_SQLSTATE = "01004"; //$NON-NLS-1$ + + private static final int THE_ERROR_CODE = 0; + + /** + * Creates a DataTruncation. The Reason is set to "Data truncation", the + * ErrorCode is set to the SQLException default value and other fields are + * set to the values supplied on this method. + * + * @param index + * the Index value of the column value or parameter that was + * truncated + * @param parameter + * true if it was a Parameter value that was truncated, false + * otherwise + * @param read + * true if the truncation occurred on a read operation, false + * otherwise + * @param dataSize + * the original size of the truncated data + * @param transferSize + * the size of the data after truncation + */ + public DataTruncation(int index, boolean parameter, boolean read, + int dataSize, int transferSize) { + super(THE_REASON, THE_SQLSTATE, THE_ERROR_CODE); + this.index = index; + this.parameter = parameter; + this.read = read; + this.dataSize = dataSize; + this.transferSize = transferSize; + } + + /** + * Gets the number of bytes of data that should have been read/written. + * + * @return the number of bytes that should have been read or written. The + * value may be set to -1 if the size is unknown. + */ + public int getDataSize() { + return dataSize; + } + + /** + * Gets the index of the column or of the parameter that was truncated. + * + * @return the index number of the column or of the parameter. + */ + public int getIndex() { + return index; + } + + /** + * Gets whether the value truncated was a parameter value or a column value. + * + * @return true if the value truncated was a Parameter value, false if it + * was a column value + */ + public boolean getParameter() { + return parameter; + } + + /** + * Gets whether the value was truncated on a read operation or a write + * operation + * + * @return true if the value was truncated on a read operation, false + * otherwise. + */ + public boolean getRead() { + return read; + } + + /** + * Gets the number of bytes of data that was actually read or written + * + * @return the number of bytes actually read/written. The value may be set + * to -1 if the size is unknown. + */ + public int getTransferSize() { + return transferSize; + } +} diff --git a/sql/src/main/java/java/sql/DatabaseMetaData.java b/sql/src/main/java/java/sql/DatabaseMetaData.java new file mode 100644 index 0000000..8c0f17c --- /dev/null +++ b/sql/src/main/java/java/sql/DatabaseMetaData.java @@ -0,0 +1,3081 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * An interface which provides comprehensive information about the database. + * <p> + * This interface is implemented by JDBC driver writers in order to provide + * information about the underlying Database capabilities and the JDBC driver + * capabilities taken together. + * <p> + * Some of the methods in this interface take String parameters which are + * Patterns. Within these string Patterns, '%' and '_' characters have special + * meanings. '%' means "match any substring of 0 or more characters". '_' means + * "match any one character". Only metadata entries that match the pattern are + * returned. If such a search pattern string is set to <code>null</code>, + * that argument's criteria are dropped from the search. + * + */ +public interface DatabaseMetaData { + + /** + * States that it may not be permitted to store <code>NULL</code> values. + */ + public static final short attributeNoNulls = 0; + + /** + * States that <code>NULL</code> values are definitely permitted. + */ + public static final short attributeNullable = 1; + + /** + * States that whether <code>NULL</code> values are permitted is unknown. + */ + public static final short attributeNullableUnknown = 2; + + /** + * States the best row identifier is <em>NOT</em> a pseudo column. + */ + public static final int bestRowNotPseudo = 1; + + /** + * States that the best row identifier is a pseudo column. + */ + public static final int bestRowPseudo = 2; + + /** + * States that the remainder of the current session is used as the scope for + * the best row identifier. + */ + public static final int bestRowSession = 2; + + /** + * States that best row identifier scope lasts only while the row is being + * used. + */ + public static final int bestRowTemporary = 0; + + /** + * States that the remainder of the current transaction is used as the scope + * for the best row identifier. + */ + public static final int bestRowTransaction = 1; + + /** + * States that the best row identifier may or may not be a pseudo column. + */ + public static final int bestRowUnknown = 0; + + /** + * States that the column might not allow <code>NULL</code> values. + */ + public static final int columnNoNulls = 0; + + /** + * States that the column definitely allows <code>NULL</code> values. + */ + public static final int columnNullable = 1; + + /** + * States that it is unknown whether the columns may be nulled. + */ + public static final int columnNullableUnknown = 2; + + /** + * For the column UPDATE_RULE, States that when the primary key is updated, + * the foreign key (imported key) is changed to agree with it. + */ + public static final int importedKeyCascade = 0; + + /** + * States deferrability. + */ + public static final int importedKeyInitiallyDeferred = 5; + + /** + * States defer-ability. + */ + public static final int importedKeyInitiallyImmediate = 6; + + /** + * For the columns UPDATE_RULE and DELETE_RULE, States that if the primary + * key has been imported, it cannot be updated or deleted. + */ + public static final int importedKeyNoAction = 3; + + /** + * States defer-ability. + */ + public static final int importedKeyNotDeferrable = 7; + + /** + * States that a primary key must not be updated when imported as a foreign + * key by some other table. Used for the column UPDATE_RULE. + */ + public static final int importedKeyRestrict = 1; + + /** + * States that when the primary key is modified (updated or deleted) the + * foreign (imported) key is changed to its default value. Applies to the + * UPDATE_RULE and DELETE_RULE columns. + */ + public static final int importedKeySetDefault = 4; + + /** + * States that when the primary key is modified (updated or deleted) the + * foreign (imported) key is changed to <code>NULL</code>. Applies to the + * UPDATE_RULE and DELETE_RULE columns. + */ + public static final int importedKeySetNull = 2; + + /** + * States that this column stores IN type parameters. + */ + public static final int procedureColumnIn = 1; + + /** + * States that this column stores INOUT type parameters. + */ + public static final int procedureColumnInOut = 2; + + /** + * States that this column stores OUT type parameters. + */ + public static final int procedureColumnOut = 4; + + /** + * States that the column stores results + */ + public static final int procedureColumnResult = 3; + + /** + * States that the column stores return values. + */ + public static final int procedureColumnReturn = 5; + + /** + * States that type of the column is unknown. + */ + public static final int procedureColumnUnknown = 0; + + /** + * States that <code>NULL</code> values are not permitted. + */ + public static final int procedureNoNulls = 0; + + /** + * States that the procedure does not return a result. + */ + public static final int procedureNoResult = 1; + + /** + * States that <code>NULL</code> values are permitted. + */ + public static final int procedureNullable = 1; + + /** + * States that whether <code>NULL</code> values are permitted is unknown. + */ + public static final int procedureNullableUnknown = 2; + + /** + * States that it is unknown whether or not the procedure returns a result. + */ + public static final int procedureResultUnknown = 0; + + /** + * States that the procedure returns a result. + */ + public static final int procedureReturnsResult = 2; + + /** + * States that the value is an SQL99 SQLSTATE value. + */ + public static final int sqlStateSQL99 = 2; + + /** + * States that the value is an SQL CLI SQLSTATE value as defined by X/Open + * (who are now know as Open Group) . + */ + public static final int sqlStateXOpen = 1; + + /** + * States that this table index is a clustered index. + */ + public static final short tableIndexClustered = 1; + + /** + * States that this table index is a hashed index. + */ + public static final short tableIndexHashed = 2; + + /** + * States this table's index is neither a clustered index, not a hashed + * index, and not a table statistics index; i.e. it is something else. + */ + public static final short tableIndexOther = 3; + + /** + * States this column has the table's statistics, and that it is returned in + * conjunction with the table's index description. + */ + public static final short tableIndexStatistic = 0; + + /** + * States that a <code>NULL</code> value is <em>NOT</em> permitted for + * this data type. + */ + public static final int typeNoNulls = 0; + + /** + * States that a <code>NULL</code> value is permitted for this data type. + */ + public static final int typeNullable = 1; + + /** + * States that it is unknown if a <code>NULL</code> value is permitted for + * this data type. + */ + public static final int typeNullableUnknown = 2; + + /** + * States that one can base all WHERE search clauses except WHERE . + */ + public static final int typePredBasic = 2; + + /** + * States that <code>WHERE</code> is the only WHERE search clause that may + * be based on this type. + */ + public static final int typePredChar = 1; + + /** + * States that this type does not support <code>WHERE</code> search + * clauses. + */ + public static final int typePredNone = 0; + + /** + * States that all WHERE search clauses may be based on this type. + */ + public static final int typeSearchable = 3; + + /** + * States that the version column is known to be not a pseudo column. + */ + public static final int versionColumnNotPseudo = 1; + + /** + * States that this version column is known to be a pseudo column. + */ + public static final int versionColumnPseudo = 2; + + /** + * States that the version column may be a pseudo column or not. + */ + public static final int versionColumnUnknown = 0; + + /** + * Returns whether all procedures returned by <code>getProcedures</code> + * can be called by the current user. + * + * @return <code>true</code> if all procedures can be called by the + * current user, <code>false</code> otherwise. + * @throws SQLException + * if there is a database error + */ + public boolean allProceduresAreCallable() throws SQLException; + + /** + * Returns whether all the tables returned by <code>getTables</code> can + * be used by the current user in a SELECT statement. + * + * @return <code>true</code> if all the tables can be used,<code>false</code> + * otherwise + * @throws SQLException + * if there is a database error + */ + public boolean allTablesAreSelectable() throws SQLException; + + /** + * Returns if a data definition statement in a transaction forces a commit + * of the transaction. + * + * @return <code>true</code> if the statement forces a commit, + * <code>false</code> otherwise + * @throws SQLException + * if there is a database error + */ + public boolean dataDefinitionCausesTransactionCommit() throws SQLException; + + /** + * Returns whether the database ignores data definition statements within a + * transaction. + * + * @return <code>true</code> if the database ignores a data definition + * statement, <code>false</code> otherwise + * @throws SQLException + * if there is a database error + */ + public boolean dataDefinitionIgnoredInTransactions() throws SQLException; + + /** + * Returns whether a visible row delete can be detected by calling + * <code>ResultSet.rowDeleted</code>. + * + * @param type + * the type of the ResultSet involved: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if the visible row delete can be detected, + * <code>false</code> otherwise + * @throws SQLException + * if there is a database error + */ + public boolean deletesAreDetected(int type) throws SQLException; + + /** + * Returns whether the return value of <code>getMaxRowSize</code> includes + * the SQL data types <code>LONGVARCHAR</code> and + * <code>LONGVARBINARY</code>. + * + * @return <code>true</code> if the return value includes + * <code>LONGVARBINARY</code> and <code>LONGVARCHAR</code>, + * otherwise <code>false</code>. + * @throws SQLException + * if there is a database error + */ + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException; + + /** + * Returns a description of the specified attribute of the specified type + * for an SQL User Defined Type (UDT) for a specified schema and catalog. + * The descriptions returned are ordered by <code>TYPE_SCHEM</code>, + * <code>TYPE_NAME</code> and ORDINAL_POSITION. The descriptions do not + * contain inherited attributes. + * <p> + * The returned ResultSet object has rows with the following column names + * and meanings: + * <ol> + * <li><code>TYPE_CAT</code> - String - the Type Catalog name (possibly + * <code>null</code>)</li> + * <li><code>TYPE_SCHEM</code> - String - the Type Schema name (possibly + * <code>null</code>)</li> + * <li><code>TYPE_NAME</code> - String - the Type name</li> + * <li><code>ATTR_NAME</code> - String - the Attribute name</li> + * <li><code>DATA_TYPE</code> - int - the Attribute type as defined in + * <code>java.sql.Types</code></li> + * <li><code>ATTR_TYPE_NAME</code> - String - the Attribute type name. + * This depends on the data source. For a <code>UDT</code> the name is + * fully qualified. For a <code>REF</code> it is both fully qualified and + * represents the target type of the reference.</li> + * <li><code>ATTR_SIZE</code> - int - the Column size. When referring to + * char and date types this value is the maximum number of characters. When + * referring to numeric types is is the precision.</li> + * <li><code>DECIMAL_DIGITS</code> - int - how many fractional digits are + * supported</li> + * <li><code>NUM_PREC_RADIX</code> - int - numeric values radix</li> + * <li><code>NULLABLE</code> - int - whether <code>NULL</code> is + * permitted: + * <ul> + * <li>DatabaseMetaData.attributeNoNulls - might not allow + * <code>NULL</code>s</li> + * <li>DatabaseMetaData.attributeNullable - <code>NULL</code>s + * definitely permitted</li> + * <li>DatabaseMetaData.attributeNullableUnknown - unknown</li> + * </ul> + * </li> + * <li><code>REMARKS</code> - String - A comment describing the attribute + * (possibly <code>null</code>)</li> + * <li>ATTR_DEF - String - Default value for the attribute (possibly + * <code>null</code>)</li> + * <li><code>SQL_DATA_TYPE</code> - int - not used</li> + * <li>SQL_DATETIME_SUB - int - not used</li> + * <li>CHAR_OCTET_LENGTH - int - For <code>CHAR</code> types, the max + * number of bytes in the column</li> + * <li>ORDINAL_POSITION - int - The Index of the column in the Table (based + * on 1)</li> + * <li>IS_NULLABLE - String - "NO" = column does not allow + * <code>NULL</code>s, "YES" = column allows <code>NULL</code>s "" = + * <code>NULL</code> status unknown</li> + * <li><code>SCOPE_CATALOG</code> - String - Catalog for table, + * <code>SCOPE</code> of Reference attribute. NULL if + * <code>DATA_TYPE</code> is not REF.</li> + * <li><code>SCOPE_SCHEMA</code> - String - Schema for table, + * <code>SCOPE</code> of Reference attribute. NULL if + * <code>DATA_TYPE</code> is not REF.</li> + * <li><code>SCOPE_TABLE</code> - String - Table name for + * <code>SCOPE</code> of Reference attribute. <code>NULL</code> if + * <code>DATA_TYPE</code> is not REF.</li> + * <li><code>SOURCE_DATA_TYPE</code> - String - The source type for user + * generated REF type or for a Distinct type. (<code>NULL</code> if + * <code>DATA_TYPE</code> is not DISTINCT or user generated REF)</li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param typeNamePattern + * a Type name. This pattern must match the type name stored in + * the database. + * @param attributeNamePattern + * an Attribute name. Must match the attribute name as stored in + * the database. + * @return a ResultSet, where each Row is an attribute description + * @throws SQLException + * if there is a database error + */ + public ResultSet getAttributes(String catalog, String schemaPattern, + String typeNamePattern, String attributeNamePattern) + throws SQLException; + + /** + * Returns a list of a table's optimal set of columns that uniquely + * identifies a row. The results are ordered by <code>SCOPE</code> (see + * below). + * <p> + * The results are returned as a table, with one entry for each column, as + * follows: + * <ol> + * <li><code>SCOPE</code> - short - the <code>SCOPE</code> of the + * result, as follows: + * <ul> + * <li>DatabaseMetaData.bestRowTemporary - very temporary, while using row + * </li> + * <li>DatabaseMetaData.bestRowTransaction - good for remainder of current + * transaction </li> + * <li>DatabaseMetaData.bestRowSession - good for remainder of database + * session </li> + * </ul> + * </li> + * <li><code>COLUMN_NAME</code> - String - the column name </li> + * <li><code>DATA_TYPE</code> - int - the Type of the data, as defined in + * <code>java.sql.Types</code> </li> + * <li><code>TYPE_NAME</code> - String - Name of the type - database + * dependent. For UDT types the name is fully qualified </li> + * <li><code>COLUMN_SIZE</code> - int - The precision of the data in the + * column </li> + * <li><code>BUFFER_LENGTH</code> - int - not used </li> + * <li><code>DECIMAL_DIGITS</code> - short - number of fractional digits + * </li> + * <li><code>PSEUDO_COLUMN</code> - short - whether this is a pseudo + * column eg. and Oracle ROWID: + * <ul> + * <li>DatabaseMetaData.bestRowUnknown - don't know whether this is a + * pseudo column</li> + * <li>DatabaseMetaData.bestRowNotPseudo - column is not pseudo</li> + * <li>DatabaseMetaData.bestRowPseudo - column is a pseudo column</li> + * </ul> + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param table + * the table name. This must match the name of the table as + * declared in the database. + * @param scope + * the <code>SCOPE</code> of interest, values as defined above + * @param nullable + * <code>true</code> = include columns that are nullable, + * <code>false</code> = do not include + * @return a ResultSet where each row is a description of a column and the + * complete set of rows is the optimal set for this table. + * @throws SQLException + * if there is a database error + */ + public ResultSet getBestRowIdentifier(String catalog, String schema, + String table, int scope, boolean nullable) throws SQLException; + + /** + * Returns the set of catalog names available in this database. The set is + * returned ordered by catalog name. + * + * @return a ResultSet containing the Catalog names, with each row + * containing one Catalog name contained as a String in the single + * column named <code>TABLE_CAT</code>. + * @throws SQLException + * if there is a database error + */ + public ResultSet getCatalogs() throws SQLException; + + /** + * Returns the separator that this database uses between a catalog name and + * table name. + * + * @return a String containing the separator + * @throws SQLException + * if there is a database error + */ + public String getCatalogSeparator() throws SQLException; + + /** + * Returns the term that the database vendor prefers term for "catalog". + * + * @return a String with the vendor's term for "catalog" + * @throws SQLException + * if there is a database error + */ + public String getCatalogTerm() throws SQLException; + + /** + * Returns a description of access rights for a table's columns. Only access + * rights matching the criteria for the column name are returned. + * <p> + * The description is returned as a ResultSet with rows of data for each + * access right, with columns as follows: + * <ol> + * <li><code>TABLE_CAT</code> - String - Catalog name (possibly + * <code>null</code>)</li> + * <li><code>TABLE_SCHEM</code> - String - Schema name (possibly + * <code>null</code>) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>COLUMN_NAME</code> - String - The Column name</li> + * <li><code>GRANTOR</code> - String - The grantor of access (possibly + * <code>null</code>)</li> + * <li><code>PRIVILEGE</code> - String - Access right - one of SELECT, + * INSERT, UPDATE, REFERENCES,...</li> + * <li><code>IS_GRANTABLE</code> - String - "YES" implies that the + * receiver can grant access to others, "NO" if the receiver cannot grant + * access to others, <code>null</code> if unknown.</li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param table + * the table name. This must match the name of the table as + * declared in the database. + * @param columnNamePattern + * the column name. This must match the name of a column in the + * table in the database. + * @return a ResultSet containing the access rights, one row for each + * privilege description + * @throws SQLException + * if there is a database error + */ + public ResultSet getColumnPrivileges(String catalog, String schema, + String table, String columnNamePattern) throws SQLException; + + /** + * Returns a description of table columns available in a specified catalog. + * Only descriptions meeting the specified Catalog, Schema, Table and Column + * names are returned. + * <p> + * The descriptions are returned as a ResultSet conforming to the following + * data layout, with one row per table column: + * <ol> + * <li><code>TABLE_CAT</code> - String - Catalog name (possibly + * <code>null</code>)</li> + * <li><code>TABLE_SCHEM</code> - String - Schema name (possibly + * <code>null</code>) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>COLUMN_NAME</code> - String - The Column name</li> + * <li><code>DATA_TYPE</code> - int - The SQL type as specified in + * <code>java.sql.Types</code></li> + * <li><code>TYPE_NAME</code> - String - Name for the data type, depends + * on database, UDT names are fully qualified</li> + * <li><code>COLUMN_SIZE</code> - int - Column size - the precision for + * numeric types, max characters for char and date types</li> + * <li><code>BUFFER_LENGTH</code> - int - Not used </li> + * <li><code>DECIMAL_DIGITS</code> - int - maximum number of fractional + * digits </li> + * <li><code>NUM_PREC_RADIX</code> - int - the Radix </li> + * <li><code>NULLABLE</code> - int - does the column allow + * <code>null</code>s: + * <ul> + * <li>DatabaseMetaData.columnNoNulls = may not allow <code>NULL</code>s</li> + * <li>DatabaseMetaData.columnNullable = does allow <code>NULL</code>s</li> + * <li>DatabaseMetaData.columnNullableUnknown = unknown <code>NULL</code> + * status</li> + * </ul> + * </li> + * <li><code>REMARKS</code> - String - A description of the column + * (possibly <code>null</code>) </li> + * <li><code>COLUMN_DEF</code> - String - Default value for the column + * (possibly <code>null</code>)</li> + * <li><code>SQL_DATA_TYPE</code> - int - not used </li> + * <li><code>SQL_DATETIME_SUB</code> - int - not used </li> + * <li><code>CHAR_OCTET_LENGTH</code> - int - maximum number of bytes in + * the char type columns </li> + * <li><code>ORDINAL_POSITION</code> - int - Column index in the table (1 + * based) </li> + * <li><code>IS_NULLABLE</code> - String - "NO" = column does not allow + * NULLs, "YES" = column allows NULLs "" = <code>NULL</code> status + * unknown</li> + * <li><code>SCOPE</code>_CATALOG - String - Catalog for table, + * <code>SCOPE</code> of Reference attribute. NULL if + * <code>DATA_TYPE</code> is not REF.</li> + * <li><code>SCOPE_SCHEMA</code> - String - Schema for table, scope of + * Reference attribute. <code>NULL</code> if <code>DATA_TYPE</code> is + * not REF.</li> + * <li><code>SCOPE_TABLE</code> - String - Table name for scope of + * Reference attribute. <code>NULL</code> if <code>DATA_TYPE</code> is + * not REF.</li> + * <li><code>SOURCE_DATA_TYPE</code> - String - The source type for user + * generated REF type or for a Distinct type. (<code>NULL</code> if + * <code>DATA_TYPE</code> is not DISTINCT or user generated REF)</li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param tableNamePattern + * the table name. This must match the name of the table as + * declared in the database. + * @param columnNamePattern + * the column name. This must match the name of a column in the + * table in the database. + * @return the descriptions as a ResultSet with rows in the form defined + * above + * @throws SQLException + * if there is a database error + */ + public ResultSet getColumns(String catalog, String schemaPattern, + String tableNamePattern, String columnNamePattern) + throws SQLException; + + /** + * Returns the database connection that created this metadata. + * + * @return the connection + * @throws SQLException + * if there is a database error + */ + public Connection getConnection() throws SQLException; + + /** + * Returns a list of foreign key columns in a given foreign key table that + * reference the primary key columns of a supplied primary key table. This + * describes how one table imports the key of another table. It would be + * expected to return a single foreign key - primary key pair in most cases. + * <p> + * The descriptions are returned as a ResultSet with one row for each + * Foreign key, with the following layout: + * <ol> + * <li><code>PKTABLE_CAT</code> - String - from the primary key table : + * Catalog (possibly <code>null</code>)</li> + * <li><code>PKTABLE_SCHEM</code> - String - from the primary key table : + * Schema (possibly <code>null</code>) </li> + * <li><code>PKTABLE_NAME</code> - String - primary key table : name + * </li> + * <li><code>PKCOLUMN_NAME</code> - String - primary key column : name</li> + * <li><code>FKTABLE_CAT</code> - String - from the foreign key table : + * the catalog name being exported (possibly <code>null</code>)</li> + * <li><code>FKTABLE_SCHEM</code> - String - foreign key table : Schema + * name being exported (possibly <code>null</code>) </li> + * <li><code>FKTABLE_NAME</code> - String - foreign key table : the name + * being exported</li> + * <li><code>FKCOLUMN_NAME</code> - String - foreign key column : the + * name being exported</li> + * <li><code>KEY_SEQ</code> - short - sequence number (in the foreign + * key)</li> + * <li><code>UPDATE_RULE</code> - short - how to treat foreign key when + * primary key is updated: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow update of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - change imported key to match + * the primary key update</li> + * <li>DatabaseMetaData.importedKeySetNull - set the imported key to + * <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - set the imported key to + * default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li><code>DELETE_RULE</code> - short - how to treat foreign key when + * primary key is deleted: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow delete of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - delete those rows that import + * a deleted key</li> + * <li>DatabaseMetaData.importedKeySetNull - set the imported key to + * <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - set the imported key to + * default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li>FK_NAME - String - foreign key name (possibly <code>null</code>)</li> + * <li>PK_NAME - String - primary key name (possibly <code>null</code>)</li> + * <li>DEFERRABILITY - short - can foreign key constraints be deferred + * until commit (see SQL92 specification for definitions)?: + * <ul> + * <li>DatabaseMetaData.importedKeyInitiallyDeferred</li> + * <li>DatabaseMetaData.importedKeyInitiallyImmediate</li> + * <li>DatabaseMetaData.importedKeyNotDeferrable</li> + * </ul> + * </li> + * </ol> + * + * @param primaryCatalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param primarySchema + * a Schema Name. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param primaryTable + * the name of the table which exports the key. It must match the + * name of the table in the database + * @param foreignCatalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param foreignSchema + * a Schema Name. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param foreignTable + * the name of the table importing the key. It must match the + * name of the table in the database + * @return a ResultSet containing rows with the descriptions of the foreign + * keys laid out according to the format defined above. + * @throws SQLException + * if there is a database error + */ + public ResultSet getCrossReference(String primaryCatalog, + String primarySchema, String primaryTable, String foreignCatalog, + String foreignSchema, String foreignTable) throws SQLException; + + /** + * Returns the major version number of the database software. + * + * @return the Major version number of the database software. + * @throws SQLException + * a database error occurred + */ + public int getDatabaseMajorVersion() throws SQLException; + + /** + * Returns the minor version number of the database software. + * + * @return the Minor version number of the database software. + * @throws SQLException + * a database error occurred + */ + public int getDatabaseMinorVersion() throws SQLException; + + /** + * Returns the name of the database software. + * + * @return a String with the name of the database software. + * @throws SQLException + * a database error occurred + */ + public String getDatabaseProductName() throws SQLException; + + /** + * Returns the version number of this database software. + * + * @return a String with the version number of the database software. + * @throws SQLException + * a database error occurred + */ + public String getDatabaseProductVersion() throws SQLException; + + /** + * Returns the default transaction isolation level for this database. + * + * @return the default transaction isolation level. One of + * <code>TRANSACTION_NONE</code>, + * <code>TRANSACTION_READ_COMMITTED</code>, + * <code>TRANSACTION_READ_UNCOMMITTED</code>, + * <code>TRANSACTION_REPEATABLE_READ</code> or + * <code>TRANSACTION_SERIALIZABLE</code>. + * @throws SQLException + * a database error occurred + */ + public int getDefaultTransactionIsolation() throws SQLException; + + /** + * Returns the JDBC driver's major version number. + * + * @return the driver's major version number + */ + public int getDriverMajorVersion(); + + /** + * Returns the JDBC driver's minor version number. + * + * @return the driver's minor version number + */ + public int getDriverMinorVersion(); + + /** + * Returns the name of this JDBC driver. + * + * @return a String containing the name of the JDBC driver + * @throws SQLException + * a database error occurred + */ + public String getDriverName() throws SQLException; + + /** + * Returns the version number of this JDBC driver. + * + * @return a String containing the complete version number of the JDBC + * driver + * @throws SQLException + * a database error occurred + */ + public String getDriverVersion() throws SQLException; + + /** + * Returns a list of the foreign key columns that reference the primary key + * columns of a specified table (the foreign keys exported by a table). + * <p> + * The list is returned as a ResultSet with a row for each of the foreign + * key columns, ordered by <code>FKTABLE_CAT</code>, + * <code>FKTABLE_SCHEM</code>, <code>FKTABLE_NAME</code>, and + * <code>KEY_SEQ</code>, with the format for each row being: + * <ol> + * <li><code>PKTABLE_CAT</code> - String - primary key table : Catalog + * (possibly <code>null</code>)</li> + * <li><code>PKTABLE_SCHEM</code> - String - primary key table : Schema + * (possibly <code>null</code>) </li> + * <li><code>PKTABLE_NAME</code> - String - primary key table : name + * </li> + * <li><code>PKCOLUMN_NAME</code> - String - primary key column : name</li> + * <li><code>FKTABLE_CAT</code> - String - foreign key table : Catalog + * name being exported (possibly <code>null</code>)</li> + * <li><code>FKTABLE_SCHEM</code> - String - foreign key table : Schema + * name being exported (possibly <code>null</code>) </li> + * <li><code>FKTABLE_NAME</code> - String - foreign key table : name + * being exported</li> + * <li><code>FKCOLUMN_NAME</code> - String - foreign key column : name + * being exported</li> + * <li>KEY_SEQ - short - sequence number in the foreign key</li> + * <li>UPDATE_RULE - short - how to treat foreign key when primary key is + * updated: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow update of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - change imported key to match + * the primary key update</li> + * <li>DatabaseMetaData.importedKeySetNull - set the imported key to + * <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - set the imported key to + * default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li>DELETE_RULE - short - how to treat foreign key when primary key is + * deleted: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow delete of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - the deletion should also + * delete rows that import a deleted key</li> + * <li>DatabaseMetaData.importedKeySetNull - it should set the imported key + * to <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - deletion sets the imported + * key to default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li>FK_NAME - String - foreign key name (possibly <code>null</code>)</li> + * <li>PK_NAME - String - primary key name (possibly <code>null</code>)</li> + * <li>DEFERRABILITY - short - defines whether foreign key constraints can + * be deferred until commit (see SQL92 specification for definitions): + * <ul> + * <li>DatabaseMetaData.importedKeyInitiallyDeferred</li> + * <li>DatabaseMetaData.importedKeyInitiallyImmediate</li> + * <li>DatabaseMetaData.importedKeyNotDeferrable</li> + * </ul> + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param table + * a table name, which must match the name of a table in the + * database + * @return a ResultSet containing a row for each of the foreign key columns, + * as defined above + * @throws SQLException + * a database error occurred + */ + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException; + + /** + * Returns a string of characters that may be used in unquoted identifier + * names. The characters a-z, A-Z, 0-9 and _ are always permitted. + * + * @return a String containing all the extra characters + * @throws SQLException + * a database error occurred + */ + public String getExtraNameCharacters() throws SQLException; + + /** + * Returns the string used to quote SQL identifiers. Returns " " (space) if + * identifier quoting not supported. + * + * @return the String used to quote SQL identifiers. + * @throws SQLException + * a database error occurred + */ + public String getIdentifierQuoteString() throws SQLException; + + /** + * Returns a list columns in a table that are both primary keys and + * referenced by the table's foreign key columns (that is, the primary keys + * imported by a table). + * <p> + * The list returned is a <code>ResultSet</code> with a row entry for each + * primary key column, ordered by <code>PKTABLE_CAT</code>, + * <code>PKTABLE_SCHEM</code>, <code>PKTABLE_NAME</code>, and + * <code>KEY_SEQ</code>, with the following format: + * <ol> + * <li><code>PKTABLE_CAT</code> - String - primary key Catalog name being + * imported (possibly <code>null</code>)</li> + * <li><code>PKTABLE_SCHEM</code> - String - primary key Schema name + * being imported (possibly <code>null</code>) </li> + * <li><code>PKTABLE_NAME</code> - String - primary key Table name being + * imported </li> + * <li><code>PKCOLUMN_NAME</code> - String - primary key column name + * being imported</li> + * <li><code>FKTABLE_CAT</code> - String - foreign key table catalog name + * (possibly <code>null</code>)</li> + * <li><code>FKTABLE_SCHEM</code> - String - foreign key table Schema + * name (possibly <code>null</code>) </li> + * <li><code>FKTABLE_NAME</code> - String - foreign key table name</li> + * <li><code>FKCOLUMN_NAME</code> - String - foreign key column name</li> + * <li>KEY_SEQ - short - sequence number in the foreign key</li> + * <li>UPDATE_RULE - short - how to treat foreign key when primary key is + * updated: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow update of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - change imported key to match + * the primary key update</li> + * <li>DatabaseMetaData.importedKeySetNull - set the imported key to + * <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - set the imported key to + * default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li>DELETE_RULE - short - how to treat foreign key when primary key is + * deleted: + * <ul> + * <li>DatabaseMetaData.importedKeyNoAction - don't allow delete of primary + * key if imported</li> + * <li>DatabaseMetaData.importedKeyCascade - delete those rows that import + * a deleted key</li> + * <li>DatabaseMetaData.importedKeySetNull - set the imported key to + * <code>null</code></li> + * <li>DatabaseMetaData.importedKeySetDefault - set the imported key to + * default values</li> + * <li>DatabaseMetaData.importedKeyRestrict - same as importedKeyNoAction</li> + * </ul> + * </li> + * <li>FK_NAME - String - foreign key name (possibly <code>null</code>)</li> + * <li>PK_NAME - String - primary key name (possibly <code>null</code>)</li> + * <li>DEFERRABILITY - short - defines whether foreign key constraints can + * be deferred until commit (see SQL92 specification for definitions): + * <ul> + * <li>DatabaseMetaData.importedKeyInitiallyDeferred</li> + * <li>DatabaseMetaData.importedKeyInitiallyImmediate</li> + * <li>DatabaseMetaData.importedKeyNotDeferrable</li> + * </ul> + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param table + * a table name, which must match the name of a table in the + * database + * @return a ResultSet containing the list of primary key columns as rows in + * the format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException; + + /** + * Returns a list of indices and statistics for a specified table. + * <p> + * The list is returned as a ResultSet, with one row for each index or + * statistic. The list is ordered by NON_UNIQUE, TYPE, INDEX_NAME, and + * ORDINAL_POSITION. Each row has the following format: + * <ol> + * <li><code>TABLE_CAT</code> - String - table catalog name (possibly + * <code>null</code>)</li> + * <li><code>TABLE_SCHEM</code> - String - Table Schema name (possibly + * <code>null</code>) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>NON_UNIQUE</code> - boolean - <code>true</code> when index + * values can be non-unique. Must be <code>false</code> when TYPE is + * tableIndexStatistic</li> + * <li><code>INDEX_QUALIFIER</code> - String : index catalog name. + * <code>null</code> when TYPE is 'tableIndexStatistic'</li> + * <li><code>INDEX_NAME</code> - String : index name. <code>null</code> + * when TYPE is 'tableIndexStatistic'</li> + * <li>TYPE - short - the index type. One of: + * <ul> + * <li>DatabaseMetaData.tableIndexStatistic - table statistics returned + * with Index descriptions</li> + * <li>DatabaseMetaData.tableIndexClustered - a clustered Index</li> + * <li>DatabaseMetaData.tableIndexHashed - a hashed Index</li> + * <li>DatabaseMetaData.tableIndexOther - other style of Index</li> + * </ul> + * </li> + * <li>ORDINAL_POSITION - short - column sequence within Index. 0 when TYPE + * is tableIndexStatistic </li> + * <li><code>COLUMN_NAME</code> - String - the column name. + * <code>null</code> when TYPE is tableIndexStatistic</li> + * <li>ASC_OR_DESC - String - column sort sequence. <code>null</code> if + * sequencing not supported or TYPE is tableIndexStatistic; otherwise "A" + * means sort ascending and "D" means sort descending. </li> + * <li>CARDINALITY - int - Number of unique values in the Index. If TYPE is + * tableIndexStatistic, this is number of rows in the table.</li> + * <li>PAGES - int - Number of pages for current Index. If TYPE is + * tableIndexStatistic, this is number of pages used for the table.</li> + * <li>FILTER_CONDITION - String - Filter condition. (possibly null) </li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schema + * a Schema Name. null is used to imply no narrowing of the + * search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param table + * a table name, which must match the name of a table in the + * database + * @param unique + * <code>true</code> means only return indices for unique + * values, <code>false</code> implies that they can be returned + * even if not unique. + * @param approximate + * <code>true</code> implies that the list can contain + * approximate or "out of data" values, <code>false</code> + * implies that all values must be precisely accurate + * @return a ResultSet containing the list of indices and statistics for the + * table, in the format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getIndexInfo(String catalog, String schema, String table, + boolean unique, boolean approximate) throws SQLException; + + /** + * Returns this driver's major JDBC version number. + * + * @return the major JDBC version number + * @throws SQLException + * a database error occurred + */ + public int getJDBCMajorVersion() throws SQLException; + + /** + * Returns the minor JDBC version number for this driver. + * + * @return the Minor JDBC Version Number + * @throws SQLException + * a database error occurred + */ + public int getJDBCMinorVersion() throws SQLException; + + /** + * Get the maximum number of hex characters in an in-line binary literal for + * this database. + * + * @return the maximum number of hex characters in an in-line binary + * literal. If the number is unlimited then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxBinaryLiteralLength() throws SQLException; + + /** + * Returns the maximum size of a Catalog name in this database. + * + * @return the maximum size in characters for a Catalog name. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxCatalogNameLength() throws SQLException; + + /** + * Returns the maximum size for a character literal in this database. + * + * @return the maximum size in characters for a character literal. If the + * limit is unknown, or the value is unlimited, then the result is + * zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxCharLiteralLength() throws SQLException; + + /** + * Returns the maximum size for a Column name for this database. + * + * @return the maximum number of characters for a Column name. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnNameLength() throws SQLException; + + /** + * Get the maximum number of columns in a GROUP BY clause for this database. + * + * @return the maximum number of columns in a GROUP BY clause. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnsInGroupBy() throws SQLException; + + /** + * Returns the maximum number of columns in an Index for this database. + * + * @return the maximum number of columns in an Index. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnsInIndex() throws SQLException; + + /** + * Returns the maximum number of columns in an ORDER BY clause for this + * database. + * + * @return the maximum number of columns in an ORDER BY clause. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnsInOrderBy() throws SQLException; + + /** + * Returns the maximum number of columns in a SELECT list for this database. + * + * @return the maximum number of columns in a SELECT list. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnsInSelect() throws SQLException; + + /** + * Returns the maximum number of columns in a table for this database. + * + * @return the maximum number of columns in a table. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxColumnsInTable() throws SQLException; + + /** + * Returns the database's maximum number of concurrent connections. + * + * @return the maximum number of connections. If the limit is unknown, or + * the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxConnections() throws SQLException; + + /** + * Returns the maximum length of a cursor name for this database. + * + * @return the maximum number of characters in a cursor name. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxCursorNameLength() throws SQLException; + + /** + * Returns the maximum length in bytes for an Index for this database. This + * covers all the parts of a composite index. + * + * @return the maximum length in bytes for an Index. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxIndexLength() throws SQLException; + + /** + * Returns the maximum number of characters for a procedure name in this + * database. + * + * @return the maximum number of character for a procedure name. If the + * limit is unknown, or the value is unlimited, then the result is + * zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxProcedureNameLength() throws SQLException; + + /** + * Returns the maximum number of bytes within a single row for this + * database. + * + * @return the maximum number of bytes for a single row. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxRowSize() throws SQLException; + + /** + * Returns the maximum number of characters in a schema name for this + * database. + * + * @return the maximum number of characters in a Schema name. If the limit + * is unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxSchemaNameLength() throws SQLException; + + /** + * Returns the maximum number of characters in an SQL statement for this + * database. + * + * @return the maximum number of characters in an SQL statement. If the + * limit is unknown, or the value is unlimited, then the result is + * zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxStatementLength() throws SQLException; + + /** + * Get the maximum number of simultaneously open active statements for this + * database. + * + * @return the maximum number of open active statements. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxStatements() throws SQLException; + + /** + * Returns the maximum size for a table name in the database. + * + * @return the maximum size in characters for a table name. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxTableNameLength() throws SQLException; + + /** + * Returns the maximum number of tables permitted in a SELECT statement for + * the database. + * + * @return the maximum number of tables permitted in a SELECT statement. If + * the limit is unknown, or the value is unlimited, then the result + * is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxTablesInSelect() throws SQLException; + + /** + * Returns the maximum number of characters in a user name for the database. + * + * @return the maximum number of characters in a user name. If the limit is + * unknown, or the value is unlimited, then the result is zero. + * @throws SQLException + * a database error occurred + */ + public int getMaxUserNameLength() throws SQLException; + + /** + * Returns a list of the math functions available with this database. These + * are used in the JDBC function escape clause and are the Open Group CLI + * math function names. + * + * @return a String which contains the list of Math functions as a comma + * separated list. + * @throws SQLException + * a database error occurred + */ + public String getNumericFunctions() throws SQLException; + + /** + * Returns a list of the primary key columns of a specified table. + * <p> + * The list is returned as a ResultSet with one row for each primary key + * column, ordered by <code>COLUMN_NAME</code>, with each row having the + * structure as follows: + * <ol> + * <li><code>TABLE_CAT</code> - String - table catalog name (possibly + * null)</li> + * <li><code>TABLE_SCHEM</code> - String - Table Schema name (possibly + * null) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>COLUMN_NAME</code> - String - The Column name </li> + * <li><code>KEY_SEQ</code> - short - the sequence number for this column + * in the primary key</li> + * <li><code>PK_NAME</code> - String - the primary key name (possibly + * null)</li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with the + * empty string used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with the empty + * string used to retrieve those without a Schema name. + * @param table + * the name of a table, which must match the name of a table in + * the database + * @return a ResultSet containing the list of keys in the format defined + * above + * @throws SQLException + * a database error occurred + */ + public ResultSet getPrimaryKeys(String catalog, String schema, String table) + throws SQLException; + + /** + * Returns a list of parameter and result columns for the stored procedures + * belonging to a specified Catalog. + * <p> + * The list is returned as a ResultSet with one row for each parameter or + * result column. The data is ordered by PROCEDURE_SCHEM and PROCEDURE_NAME, + * while for each procedure, the return value (if any) is first, followed by + * the parameters in the order they appear in the stored procedure call, + * followed by ResultSet columns in column number order. Each row has the + * following structure: + * <ol> + * <li>PROCEDURE_CAT - String - the procedure catalog name</li> + * <li>PROCEDURE_SCHEM - String - the procedure schema name (possibly null) + * </li> + * <li>PROCEDURE_NAME - String - the procedure name</li> + * <li><code>COLUMN_NAME</code> - String - the name of the column</li> + * <li>COLUMN_TYPE - short - the kind of column or parameter, as follows: + * <ul> + * <li>DatabaseMetaData.procedureColumnUnknown - type unknown</li> + * <li>DatabaseMetaData.procedureColumnIn - an IN parameter</li> + * <li>DatabaseMetaData.procedureColumnInOut - an INOUT parameter</li> + * <li>DatabaseMetaData.procedureColumnOut - an OUT parameter</li> + * <li>DatabaseMetaData.procedureColumnReturn - a return value</li> + * <li>DatabaseMetaData.procedureReturnsResult - a result column in a + * result set</li> + * </ul> + * </li> + * <li><code>DATA_TYPE</code> - int - the SQL type of the data, as in + * <code>java.sql.Types</code> </li> + * <li><code>TYPE_NAME</code> - String - the SQL type name, for a UDT it + * is fully qualified</li> + * <li>PRECISION - int - the precision</li> + * <li>LENGTH - int - the length of the data in bytes </li> + * <li>SCALE - short - the scale for numeric types</li> + * <li>RADIX - short - the Radix for numeric data (typically 2 or 10) </li> + * <li>NULLABLE - short - can the data contain null: + * <ul> + * <li>DatabaseMetaData.procedureNoNulls - <code>NULL</code>s not + * permitted</li> + * <li>DatabaseMetaData.procedureNullable - <code>NULL</code>s are + * permitted </li> + * <li>DatabaseMetaData.procedureNullableUnknown - <code>NULL</code> + * status unknown </li> + * </ul> + * </li> + * <li><code>REMARKS</code> - String - an explanatory comment about the + * data item </li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. null is used to imply no narrowing of + * the search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param procedureNamePattern + * a pattern that must match the name of the procedure stored in + * the database + * @param columnNamePattern + * a column name pattern. The name must match the column name + * stored in the database. + * @return a ResultSet with the list of parameter and result columns in the + * format defined above + * @throws SQLException + * a database error occurred + */ + public ResultSet getProcedureColumns(String catalog, String schemaPattern, + String procedureNamePattern, String columnNamePattern) + throws SQLException; + + /** + * Returns a list of the stored procedures available in a specified catalog. + * <p> + * The list is returned as a ResultSet with one row for each stored + * procedure, ordered by PROCEDURE_SCHEME and PROCEDURE_NAME, with the data + * in each row as follows: + * <ol> + * <li><code>PROCEDURE_CAT</code> - String : the procedure catalog name</li> + * <li><code>PROCEDURE_SCHEM</code> - String : the procedure schema name + * (possibly <code>null</code>) </li> + * <li><code>PROCEDURE_NAME</code> - String : the procedure name</li> + * <li><code>Reserved</code></li> + * <li><code>Reserved</code></li> + * <li><code>Reserved</code></li> + * <li><code>REMARKS</code> - String - information about the procedure</li> + * <li><code>PROCEDURE_TYPE</code> - short : one of: + * <ul> + * <li>DatabaseMetaData.procedureResultUnknown - procedure may return a + * result </li> + * <li>DatabaseMetaData.procedureNoResult - procedure does not return a + * result</li> + * <li>DatabaseMetaData.procedureReturnsResult - procedure definitely + * returns a result</li> + * </ul> + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. null is used to imply no narrowing of + * the search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param procedureNamePattern + * a procedure name pattern, which must match the procedure name + * stored in the database + * @return a ResultSet where each row is a description of a stored procedure + * in the format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getProcedures(String catalog, String schemaPattern, + String procedureNamePattern) throws SQLException; + + /** + * Returns the database vendor's preferred name for "procedure". + * + * @return a String with the vendor's preferred name for "procedure" + * @throws SQLException + * a database error occurred + */ + public String getProcedureTerm() throws SQLException; + + /** + * Returns the result set's default hold-ability. + * + * @return one of <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or + * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> + * @throws SQLException + * a database error occurred + */ + public int getResultSetHoldability() throws SQLException; + + /** + * Returns a list of the schema names in the database. The list is returned + * as a ResultSet, ordered by the Schema name, with one row per Schema in + * the following format: + * <ol> + * <li><code>TABLE_SCHEM</code> - String - the Schema name</li> + * <li><code>TABLE_CAT</code>ALOG - String - the Catalog name (possibly + * null) </li> + * </ol> + * + * @return a ResultSet with one row for each schema in the format defined + * above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getSchemas() throws SQLException; + + /** + * Returns the database vendor's preferred term for "schema". + * + * @return a String which is the vendor's preferred term for schema + * @throws SQLException + * a database error occurred + */ + public String getSchemaTerm() throws SQLException; + + /** + * Returns the string that is used to escape wildcard characters. This + * string is used to escape the '_' and '%' wildcard characters in catalog + * search strings which are a pattern and so which use the wildcard + * characters. '_' is used to represent any single character wile '%' is + * used for a sequence of zero or more characters. + * + * @return a String used to escape the wildcard characters + * @throws SQLException + * a database error occurred + */ + public String getSearchStringEscape() throws SQLException; + + /** + * Returns a list of all the SQL keywords that are NOT also SQL92 keywords + * for the database. + * + * @return a String containing the list of SQL keywords in a comma separated + * format. + * @throws SQLException + * a database error occurred + */ + public String getSQLKeywords() throws SQLException; + + /** + * States the type of SQLState value returned by SQLException.getSQLState. + * This can either be the X/Open (now known as Open Group) SQL CLI form or + * the SQL99 form. + * + * @return an integer, which is either DatabaseMetaData.sqlStateSQL99 or + * DatabaseMetaData.sqlStateXOpen. + * @throws SQLException + * a database error occurred + */ + public int getSQLStateType() throws SQLException; + + /** + * Returns a list of string functions available with the database. These + * functions are used in JDBC function escape clause and follow the Open + * Group CLI string function names definition. + * + * @return a String containing the list of string functions in comma + * separated format. + * @throws SQLException + * a database error occurred + */ + public String getStringFunctions() throws SQLException; + + /** + * Returns a listing of the hierarchies of tables in a specified schema in + * the database. + * <p> + * The listing only contains entries for tables that have a super table. + * Super and sub tables must be defined in the same Catalog and Schema. The + * list is returned as a ResultSet, with one row for each table that has a + * super table, in the following format: + * <ol> + * <li><code>TABLE_CAT</code> - String - table catalog name (possibly + * null)</li> + * <li><code>TABLE_SCHEM</code> - String - Table Schema name (possibly + * null) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li>SUPER<code>TABLE_NAME</code> - String - The Super Table name + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. null is used to imply no narrowing of + * the search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param tableNamePattern + * a Table Name, which should match the Table name as stored in + * the database. it may be a fully qualified name. If it is fully + * qualified the Catalog Name and Schema Name parameters are + * ignored. + * @return a ResultSet with one row for each table which has a super table, + * in the format defined above. An empty ResultSet is returned if + * the database does not support table hierarchies. + * @throws SQLException + * a database error occurred + */ + public ResultSet getSuperTables(String catalog, String schemaPattern, + String tableNamePattern) throws SQLException; + + /** + * Returns the User Defined Type (UDT) hierarchies for a given schema. Only + * the immediate parent/child relationship is described. If a UDT does not + * have a direct supertype, it is not listed. + * <p> + * The listing is returned as a ResultSet where there is one row for a + * specific UDT which describes its supertype, with the data organized in + * columns as follows: + * <ol> + * <li><code>TYPE_CAT</code> - String - the UDT Catalog name (possibly + * null)</li> + * <li><code>TYPE_SCHEM</code> - String - the UDT Schema name (possibly + * null) </li> + * <li><code>TYPE_NAME</code> - String - the UDT type name </li> + * <li>SUPER<code>TYPE_CAT</code> - String - direct supertype's Catalog + * name (possibly null)</li> + * <li>SUPER<code>TYPE_SCHEM</code> - String - direct supertype's Schema + * name (possibly null) </li> + * <li>SUPER<code>TYPE_NAME</code> - String - direct supertype's name + * </li> + * </ol> + * + * @param catalog + * the Catalog name. "" means get the UDTs without a catalog. + * null means don't use the catalog name to restrict the search. + * @param schemaPattern + * the Schema pattern name. "" means get the UDT's without a + * schema. + * @param typeNamePattern + * the UDT name pattern. This may be a fully qualified name. When + * a fully qualified name is specified, the Catalog name and + * Schema name parameters are ignored. + * @return a ResultSet in which each row gives information about a + * particular UDT in the format defined above. An empty ResultSet is + * returned for a database that does not support type hierarchies. + * @throws SQLException + * a database error occurred + */ + public ResultSet getSuperTypes(String catalog, String schemaPattern, + String typeNamePattern) throws SQLException; + + /** + * Returns a list of system functions available with the database. These are + * names used in the JDBC function escape clause and are Open Group CLI + * function names. + * + * @return a String containing the list of system functions in a comma + * separated format + * @throws SQLException + * a database error occurred + */ + public String getSystemFunctions() throws SQLException; + + /** + * Returns a description of access rights for each table present in a + * catalog. Table privileges can apply to one or more columns in the table - + * but are not guaranteed to apply to all columns. + * <p> + * The privileges are returned as a ResultSet, with one row for each + * privilege, ordered by <code>TABLE_SCHEM</code>, + * <code>TABLE_NAME</code>, PRIVILEGE, and each row has data as defined + * in the following column definitions: + * <ol> + * <li><code>TABLE_CAT</code> - String - table catalog name (possibly + * null)</li> + * <li><code>TABLE_SCHEM</code> - String - Table Schema name (possibly + * null) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li>GRANTOR - String - who granted the access</li> + * <li>GRANTEE - String - who received the access grant </li> + * <li>PRIVILEGE - String - the type of access granted - one of SELECT, + * INSERT, UPDATE, REFERENCES,... </li> + * <li>IS_GRANTABLE - String - "YES" implies the grantee can grant access + * to others, "NO" implies guarantee cannot grant access to others, null + * means this status is unknown</li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. null is used to imply no narrowing of + * the search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param tableNamePattern + * a Table Name, which should match the Table name as stored in + * the database. + * @return a ResultSet containing a list with one row for each table in the + * format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getTablePrivileges(String catalog, String schemaPattern, + String tableNamePattern) throws SQLException; + + /** + * Returns a description of the tables in a specified catalog. + * <p> + * The descriptions are returned as rows in a ResultSet, one row for each + * Table. The ResultSet is ordered by <code>TABLE_TYPE</code>, + * <code>TABLE_SCHEM</code> and <code>TABLE_NAME</code>. Each row in + * the ResultSet consists of a series of columns as follows: + * <ol> + * <li><code>TABLE_CAT</code> - String - table catalog name (possibly + * null)</li> + * <li><code>TABLE_SCHEM</code> - String - Table Schema name (possibly + * null) </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>TABLE_TYPE</code> - String - Typical names include "TABLE", + * "VIEW", "SYSTEM TABLE", "ALIAS", "SYNONYM", "GLOBAL TEMPORARY"</li> + * <li><code>REMARKS</code> - String - A comment describing the table + * </li> + * <li><code>TYPE_CAT</code> - String - the 'Types' catalog(possibly + * null)</li> + * <li><code>TYPE_SCHEM</code> - String - the 'Types' schema(possibly + * null) </li> + * <li><code>TYPE_NAME</code> - String - the 'Types' name (possibly null) + * </li> + * <li><code>SELF_REFERENCING_COL_NAME</code> - String - the name of a + * designated identifier column in a typed table (possibly null) </li> + * <li>REF_GENERATION - String - one of the following values : "SYSTEM" | + * "USER" | "DERIVED" - specifies how values in the + * <code>SELF_REFERENCING_COL_NAME</code> are created (possibly null) + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. null is used to imply no narrowing of + * the search using Schema Name. Otherwise, the name must match a + * Schema name in the database, with "" used to retrieve those + * without a Schema name. + * @param tableNamePattern + * a Table Name, which should match the Table name as stored in + * the database. + * @param types + * a list of table types to include in the list. null implies + * list all types. + * @return a ResultSet with one row per table in the format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getTables(String catalog, String schemaPattern, + String tableNamePattern, String[] types) throws SQLException; + + /** + * Returns a list of table types supported by the database. + * <p> + * The list is returned as a ResultSet with one row per table type, ordered + * by the table type. The information in the ResultSet is structured into a + * single column per row, as follows: + * <ol> + * <li><code>TABLE_TYPE</code> - String - the Table Type. Typical names + * include "TABLE", "VIEW", "SYSTEM TABLE", "ALIAS", "SYNONYM", "GLOBAL + * TEMPORARY" </li> + * </ol> + * + * @return a ResultSet with one row per table type in the format defined + * above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getTableTypes() throws SQLException; + + /** + * Returns a list of time and date functions available for the database. + * + * @return a String contain a comma separated list of the time and date + * functions. + * @throws SQLException + * a database error occurred + */ + public String getTimeDateFunctions() throws SQLException; + + /** + * Get a list of the standard SQL Types supported by this database. The list + * is returned as a ResultSet, with one row for each type, ordered by the + * <code>DATA_TYPE</code> value, where the data in each row is structured + * into the following columns: + * <ol> + * <li><code>TYPE_NAMR</code> - String : the Type name</li> + * <li><code>DATA_TYPE</code> - int : the SQL data type value as defined + * in <code>java.sql.Types</code></li> + * <li><code>PRECISION</code> - int - the maximum precision of the type</li> + * <li><code>LITERAL_PREFIX</code> - String : the prefix to be used when + * quoting a literal value (possibly <code>null</code>)</li> + * <li><code>LITERAL_SUFFIX</code> - String : the suffix to be used when + * quoting a literal value (possibly <code>null</code>)</li> + * <li><code>CREATE_PARAMS</code> - String : params used when creating + * the type (possibly <code>null</code>)</li> + * <li><code>NULLABLE</code> - short : shows if the value is null-able: + * <ul> + * <li>DatabaseMetaData.typeNoNulls : <code>NULL</code>s not permitted</li> + * <li>DatabaseMetaData.typeNullable : <code>NULL</code>s are permitted + * </li> + * <li>DatabaseMetaData.typeNullableUnknown : <code>NULL</code> status + * unknown </li> + * </ul> + * </li> + * <li>CASE_SENSITIVE - boolean : true if the type is case sensitive</li> + * <li>SEARCHABLE - short : how this type can be used with WHERE clauses: + * <ul> + * <li>DatabaseMetaData.typePredNone - cannot be used </li> + * <li>DatabaseMetaData.typePredChar - support for WHERE...LIKE only</li> + * <li>DatabaseMetaData.typePredBasic - support except for WHERE...LIKE</li> + * <li>DatabaseMetaData.typeSearchable - support for all WHERE clauses</li> + * </ul> + * </li> + * <li>UNSIGNED_ATTRIBUTE - boolean - the type is unsigned or not </li> + * <li>FIXED_PREC_SCALE - boolean - fixed precision = it can be used as a + * money value </li> + * <li>AUTO_INCREMENT - boolean - can be used as an auto-increment value + * </li> + * <li>LOCAL_<code>TYPE_NAME</code> - String - a localized version of + * the type name (possibly null)</li> + * <li>MINIMUM_SCALE - short - the minimum scale supported </li> + * <li>MAXIMUM_SCALE - short - the maximum scale supported </li> + * <li>SQL_<code>DATA_TYPE</code> - int - not used </li> + * <li>SQL_DATETIME_SUB - int - not used </li> + * <li>NUM_PREC_RADIX - int - number radix (typically 2 or 10) </li> + * </ol> + * + * @return a ResultSet which is structured as described above + * @throws SQLException + * a database error occurred + */ + public ResultSet getTypeInfo() throws SQLException; + + /** + * Returns a description of the User Defined Types (UDTs) defined in a given + * schema, which includes the types DISTINCT, STRUCT and JAVA_OBJECT. + * <p> + * The types matching the supplied the specified Catalog, Schema, Type Name + * and Type are returned as rows in a ResultSet with columns of information + * as follows: + * <ol> + * <li><code>TABLE_CAT</code> - String - Catalog name (possibly null)</li> + * <li><code>TABLE_SCHEM</code> - String - Schema name (possibly null) + * </li> + * <li><code>TABLE_NAME</code> - String - The Table name </li> + * <li><code>CLASS_NAME</code> - String - The Java class name</li> + * <li><code>DATA_TYPE</code> - int - The SQL type as specified in + * <code>java.sql.Types</code>. One of DISTINCT, STRUCT and JAVA_OBJECT</li> + * <li><code>REMARKS</code> - String - A comment which describes the type + * </li> + * <li><code>BASE_TYPE</code> - short - A type code. For a DISTINCT type, + * the source type. For a structured type this is the type that implements + * the user generated reference type of the + * <code>SELF_REFERENCING_COLUMN</code>. This is defined in + * <code>java.sql.Types</code>, and will be <code>null</code> if the + * <code>DATA_TYPE</code> does not match these criteria.</li> + * </ol> + * If the driver does not support UDTs, the ResultSet will be empty. + * + * @param catalog + * a Catalog Name. null is used to imply no narrowing of the + * search using Catalog Name. Otherwise, the name must match a + * Catalog Name held in the database, with "" used to retrieve + * those without a Catalog Name. + * @param schemaPattern + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param typeNamePattern + * a Type Name, which should match a Type name as stored in the + * database. It may be fully qualified. + * @param types + * a list of the UDT types to include in the list - one of + * DISTINCT, STRUCT or JAVA_OBJECT. + * @return a ResultSet in the format described above + * @throws SQLException + * a database error occurred + */ + public ResultSet getUDTs(String catalog, String schemaPattern, + String typeNamePattern, int[] types) throws SQLException; + + /** + * Returns the URL for this database. + * + * @return the URL for the database. <code>null</code> if it cannot be + * generated. + * @throws SQLException + * a database error occurred + */ + public String getURL() throws SQLException; + + /** + * Determine the user name as known by the database. + * + * @return the user name + * @throws SQLException + * a database error occurred + */ + public String getUserName() throws SQLException; + + /** + * Returns which of a table's columns are automatically updated when any + * value in a row is updated. + * <p> + * The result is laid-out in the following columns: + * <ol> + * <li><code>SCOPE</code> - short - not used </li> + * <li><code>COLUMN_NAME</code> - String - Column name</li> + * <li><code>DATA_TYPE</code> - int - The SQL data type, as defined in + * <code>java.sql.Types</code> </li> + * <li><code>TYPE_NAME</code> - String - The SQL type name, data source + * dependent </li> + * <li><code>COLUMN_SIZE</code> - int - Precision for numeric types </li> + * <li><code>BUFFER_LENGTH</code> - int - Length of a column value in + * bytes </li> + * <li><code>DECIMAL_DIGITS</code> - short - Number of digits after the + * decimal point </li> + * <li><code>PSEUDO_COLUMN</code> - short - If this is a pseudo-column + * (for example, an Oracle ROWID): + * <ul> + * <li>DatabaseMetaData.bestRowUnknown - don't know whether this is a + * pseudo column</li> + * <li>DatabaseMetaData.bestRowNotPseudo - column is not pseudo</li> + * <li>DatabaseMetaData.bestRowPseudo - column is a pseudo column</li> + * </ul> + * </li> + * </ol> + * + * @param catalog + * a Catalog Name. <code>null</code> is used to imply no + * narrowing of the search using Catalog Name. Otherwise, the + * name must match a Catalog Name held in the database, with "" + * used to retrieve those without a Catalog Name. + * @param schema + * a Schema Name Pattern. <code>null</code> is used to imply no + * narrowing of the search using Schema Name. Otherwise, the name + * must match a Schema name in the database, with "" used to + * retrieve those without a Schema name. + * @param table + * a table name. It must match the name of a table in the + * database. + * @return a ResultSet containing the descriptions, one row for each column, + * in the format defined above. + * @throws SQLException + * a database error occurred + */ + public ResultSet getVersionColumns(String catalog, String schema, + String table) throws SQLException; + + /** + * Determine if a visible row insert can be detected by calling + * ResultSet.rowInserted. + * + * @param type + * the ResultSet type. This may be one of + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> or + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code> or + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * @return <code>true</code> if ResultSet.rowInserted detects a visible + * row insert otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean insertsAreDetected(int type) throws SQLException; + + /** + * Determine whether a fully qualified table name is prefixed or suffixed to + * a fully qualified table name. + * + * @return <code>true</code> if the catalog appears at the start of a + * fully qualified table name, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean isCatalogAtStart() throws SQLException; + + /** + * Determine if the database is in read-only mode. + * + * @return <code>true</code> if the database is in read-only mode, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean isReadOnly() throws SQLException; + + /** + * Determine if updates are made to a copy of, or directly on, Large Objects + * (LOBs). + * + * @return <code>true</code> if updates are made to a copy of the Large + * Object, <code>false</code> otherwise + * @throws SQLException + * a database error occurred + */ + public boolean locatorsUpdateCopy() throws SQLException; + + /** + * Determine if the database handles concatenations between + * <code>NULL</code> and non-<code>NULL</code> values by producing a + * <code>NULL</code> output. + * + * @return <code>true</code> if <code>NULL</code> to non-<code>NULL</code> + * concatenations produce a <code>NULL</code> result, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean nullPlusNonNullIsNull() throws SQLException; + + /** + * Determine if <code>NULL</code> values are always sorted to the end of + * sorted results regardless of requested sort order. This means that they + * will appear at the end of sorted lists whatever other non-<code>NULL</code> + * values may be present. + * + * @return <code>true</code> if <code>NULL</code> values are sorted at + * the end, <code>false</code> otherwise + * @throws SQLException + * a database error occurred + */ + public boolean nullsAreSortedAtEnd() throws SQLException; + + /** + * Determine if <code>NULL</code> values are always sorted at the start of + * the sorted list, irrespective of the sort order. This means that they + * appear at the start of sorted lists, whatever other values may be + * present. + * + * @return <code>true</code> if <code>NULL</code> values are sorted at + * the start, <code>false</code> otherwise + * @throws SQLException + * a database error occurred + */ + public boolean nullsAreSortedAtStart() throws SQLException; + + /** + * Determine if <code>NULL</code> values are sorted high - i.e. they are + * sorted as if they are higher than any other values. + * + * @return <code>true</code> if <code>NULL</code> values are sorted + * high, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean nullsAreSortedHigh() throws SQLException; + + /** + * Determine if <code>NULL</code> values are sorted low - ie they are + * sorted as if they are lower than any other values. + * + * @return <code>true</code> if <code>NULL</code> values are sorted low, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean nullsAreSortedLow() throws SQLException; + + /** + * Determine if deletes made by others are visible, for a specified + * ResultSet type. + * + * @param type + * the type of the ResultSet. It may be either + * <code>ResultSet.TYPE_FORWARD_ONLY</code> or + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>) + * @return <code>true</code> if others' deletes are visible, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean othersDeletesAreVisible(int type) throws SQLException; + + /** + * Determine if inserts made by others are visible, for a specified + * ResultSet type. + * + * @param type + * the type of the ResultSet. May be + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, or + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if others' inserts are visible otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean othersInsertsAreVisible(int type) throws SQLException; + + /** + * Determine if updates made by others are visible, for a specified + * ResultSet type. + * + * @param type + * the type of the ResultSet. May be + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, or + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if others' inserts are visible otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean othersUpdatesAreVisible(int type) throws SQLException; + + /** + * Determine if a ResultSet's own deletes are visible, for a specified + * ResultSet type. + * + * @param type + * the type of the ResultSet: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if the delete's are seen by the own ResultSet + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean ownDeletesAreVisible(int type) throws SQLException; + + /** + * Determine if its own inserts are visible to a given ResultSet type. + * + * @param type + * the type of the ResultSet: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if inserts are visible for this type + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean ownInsertsAreVisible(int type) throws SQLException; + + /** + * Determine if for a supplied type of ResultSet, the ResultSet's own + * updates are visible. + * + * @param type + * the type of the ResultSet: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if updates are visible to in this ResultSet + * type otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean ownUpdatesAreVisible(int type) throws SQLException; + + /** + * Determine whether the database treats SQL identifiers that are in mixed + * case (and unquoted) as case insensitive. If true then the database stores + * them in lower case. + * + * @return <code>true</code> if unquoted SQL identifiers are stored in + * lower case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesLowerCaseIdentifiers() throws SQLException; + + /** + * Determine whether the database considers mixed case quoted SQL + * identifiers as case insensitive and stores them in lower case. + * + * @return <code>true</code> if quoted SQL identifiers are stored in lower + * case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException; + + /** + * Determine whether the database considers mixed case unquoted SQL + * identifiers as case insensitive and stores them in mixed case. + * + * @return <code>true</code> if unquoted SQL identifiers as stored in + * mixed case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesMixedCaseIdentifiers() throws SQLException; + + /** + * Determine whether the database considers identifiers as case insensitive + * if they are mixed case quoted SQL. The database stores them in mixed + * case. + * + * @return <code>true</code> if quoted SQL identifiers are stored in mixed + * case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException; + + /** + * Determine whether the database considers mixed case unquoted SQL + * identifiers as case insensitive and stores them in upper case. + * + * @return <code>true</code> if unquoted SQL identifiers are stored in + * upper case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesUpperCaseIdentifiers() throws SQLException; + + /** + * Determine whether the database considers mixed case quoted SQL + * identifiers as case insensitive and stores them in upper case. + * + * @return <code>true</code> if quoted SQL identifiers are stored in upper + * case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException; + + /** + * Determine if the database supports ALTER TABLE operation with add column. + * + * @return <code>true</code> if ALTER TABLE with add column is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsAlterTableWithAddColumn() throws SQLException; + + /** + * Determine if the database supports ALTER TABLE operation with drop + * column. + * + * @return <code>true</code> if ALTER TABLE with drop column is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsAlterTableWithDropColumn() throws SQLException; + + /** + * Determine if the database supports the ANSI92 entry level SQL grammar. + * + * @return <code>true</code> if the ANSI92 entry level SQL grammar is + * supported, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsANSI92EntryLevelSQL() throws SQLException; + + /** + * Determine if the database supports the ANSI92 full SQL grammar. + * + * @return <code>true</code> if the ANSI92 full SQL grammar is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsANSI92FullSQL() throws SQLException; + + /** + * Determine if the database supports the ANSI92 intermediate SQL Grammar. + * + * @return <code>true</code> if the ANSI92 intermediate SQL grammar is + * supported, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsANSI92IntermediateSQL() throws SQLException; + + /** + * Determine if the database supports Batch Updates. + * + * @return <code>true</code> if batch updates are supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsBatchUpdates() throws SQLException; + + /** + * Determine whether catalog names may be used in data manipulation + * statements. + * + * @return <code>true</code> if catalog names can be used in data + * manipulation statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCatalogsInDataManipulation() throws SQLException; + + /** + * Determine if catalog names can be used in Index Definition statements. + * + * @return <code>true</code> if catalog names can be used in Index + * Definition statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCatalogsInIndexDefinitions() throws SQLException; + + /** + * Determine if catalog names can be used in privilege definition + * statements. + * + * @return <code>true</code> if catalog names can be used in privilege + * definition statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException; + + /** + * Determine if catalog names can be used in procedure call statements. + * + * @return <code>true</code> if catalog names can be used in procedure + * call statements. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCatalogsInProcedureCalls() throws SQLException; + + /** + * Determine if catalog names may be used in table definition statements. + * + * @return <code>true</code> if catalog names can be used in definition + * statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCatalogsInTableDefinitions() throws SQLException; + + /** + * Determine if the database supports column aliasing. + * <p> + * If aliasing is supported, then the SQL AS clause is used to provide names + * for computed columns and provide alias names for columns. + * + * @return <code>true</code> if column aliasing is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsColumnAliasing() throws SQLException; + + /** + * Determine if the database supports the CONVERT operation between SQL + * types. + * + * @return <code>true</code> if the CONVERT operation is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsConvert() throws SQLException; + + /** + * Determine if the database supports CONVERT operation for two supplied SQL + * types. + * + * @param fromType + * the Type to convert from, as defined by + * <code>java.sql.Types</code> + * @param toType + * the Type to convert to, as defined by + * <code>java.sql.Types</code> + * @return <code>true</code> if the CONVERT operation is supported for + * these types, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsConvert(int fromType, int toType) + throws SQLException; + + /** + * Determine if the database supports the Core SQL Grammar for ODBC. + * + * @return <code>true</code> if the Core SQL Grammar is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCoreSQLGrammar() throws SQLException; + + /** + * Determine if the database supports correlated sub-queries. + * + * @return <code>true</code> if the database does support correlated + * sub-queries and <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsCorrelatedSubqueries() throws SQLException; + + /** + * Determine if the database allows both data definition and data + * manipulation statements inside a transaction. + * + * @return <code>true</code> if both types of statement are permitted, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsDataDefinitionAndDataManipulationTransactions() + throws SQLException; + + /** + * Determine if the database only allows data manipulation statements inside + * a transaction. + * + * @return <code>true</code> if only data manipulation statements are + * permitted, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsDataManipulationTransactionsOnly() + throws SQLException; + + /** + * Determine if table correlation names are restricted to be different from + * the names of the tables, when they are supported. + * + * @return <code>true</code> if correlation names must be different to + * table names, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsDifferentTableCorrelationNames() throws SQLException; + + /** + * Determine whether expressions in ORDER BY lists are supported. + * + * @return <code>true</code> if expressions in ORDER BY lists are + * supported. + * @throws SQLException + * a database error occurred + */ + public boolean supportsExpressionsInOrderBy() throws SQLException; + + /** + * Determine whether the Extended SQL Grammar for ODBC is supported. + * + * @return <code>true</code> if the Extended SQL Grammar is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsExtendedSQLGrammar() throws SQLException; + + /** + * Determine if the database supports full nested outer joins. + * + * @return <code>true</code> if full nested outer joins are supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsFullOuterJoins() throws SQLException; + + /** + * Determine if auto generated keys can be returned when a statement + * executes. + * + * @return <code>true</code> if auto generated keys can be returned, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsGetGeneratedKeys() throws SQLException; + + /** + * Determine if the database supports a form of GROUP BY clause. + * + * @return <code>true</code> if a form of GROUP BY clause is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsGroupBy() throws SQLException; + + /** + * Determine if the database supports using a column name in a GROUP BY + * clause not included in the SELECT statement as long as all of the columns + * in the SELECT statement are used in the GROUP BY clause. + * + * @return <code>true</code> if GROUP BY clauses can use column names in + * this way, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsGroupByBeyondSelect() throws SQLException; + + /** + * Determine if the database supports using a column name in a GROUP BY + * clause that is not in the SELECT statement. + * + * @return <code>true</code> if GROUP BY clause can use a column name not + * in the SELECT statement, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsGroupByUnrelated() throws SQLException; + + /** + * Determine whether the database supports SQL Integrity Enhancement + * Facility. + * + * @return <code>true</code> if the Integrity Enhancement Facility is + * supported, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsIntegrityEnhancementFacility() throws SQLException; + + /** + * Determine if the database supports using a LIKE escape clause. + * + * @return <code>true</code> if LIKE escape clause is supported, + * <code>false</code> otherwise + * @throws SQLException + * a database error occurred + */ + public boolean supportsLikeEscapeClause() throws SQLException; + + /** + * Determine if the database provides limited support for outer Join + * operations. + * + * @return <code>true</code> if there is limited support for outer Join + * operations, <code>false</code> otherwise. This will be + * <code>true</code> if <code>supportsFullOuterJoins</code> + * returns <code>true</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsLimitedOuterJoins() throws SQLException; + + /** + * Determine if the database supports Minimum SQL Grammar for ODBC. + * + * @return <code>true</code> if the Minimum SQL Grammar is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMinimumSQLGrammar() throws SQLException; + + /** + * Determine if the database treats mixed case unquoted SQL identifiers as + * case sensitive storing them in mixed case. + * + * @return <code>true</code> if unquoted SQL identifiers are stored in + * mixed case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMixedCaseIdentifiers() throws SQLException; + + /** + * Determine whether the database considers mixed case quoted SQL + * identifiers as case sensitive, storing them in mixed case. + * + * @return <code>true</code> if quoted SQL identifiers are stored in mixed + * case, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException; + + /** + * Determine if it is possible for a single CallableStatement to return + * multiple ResultSets simultaneously. + * + * @return <code>true</code> if a single CallableStatement can return + * multiple ResultSets simultaneously, <code>false</code> + * otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMultipleOpenResults() throws SQLException; + + /** + * Determine whether retrieving multiple ResultSets from a single call to + * the <code>execute</code> method is supported. + * + * @return <code>true</code> if multiple ResultSets can be retrieved, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMultipleResultSets() throws SQLException; + + /** + * Determine whether multiple transactions in progress at at time on + * different connections are supported. + * + * @return <code>true</code> if multiple open transactions are supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsMultipleTransactions() throws SQLException; + + /** + * Determine whether call-able statements with named parameters is + * supported. + * + * @return <code>true</code> if named parameters can be used with + * call-able statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsNamedParameters() throws SQLException; + + /** + * Determine if columns in the database can be defined as non-nullable. + * + * @return <code>true</code> if Columns can be defined non-nullable, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsNonNullableColumns() throws SQLException; + + /** + * Determine whether keeping Cursors open across Commit operations is + * supported. + * + * @return <code>true</code> if Cursors can be kept open across Commit + * operations, <code>false</code> if they might get closed. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOpenCursorsAcrossCommit() throws SQLException; + + /** + * Determine if the database can keep Cursors open across Rollback + * operations. + * + * @return <code>true</code> if Cursors can be kept open across Rollback + * operations, <code>false</code> if they might get closed. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOpenCursorsAcrossRollback() throws SQLException; + + /** + * Determine whether keeping Statements open across Commit operations is + * supported. + * + * @return <code>true</code> if Statements can be kept open, + * <code>false</code> if they might not. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOpenStatementsAcrossCommit() throws SQLException; + + /** + * Determine whether keeping Statements open across Rollback operations is + * supported. + * + * @return <code>true</code> if Statements can be kept open, + * <code>false</code> if they might not. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOpenStatementsAcrossRollback() throws SQLException; + + /** + * Determine whether using a column in an ORDER BY clause that is not in the + * SELECT statement is supported. + * + * @return <code>true</code> if it is possible to ORDER using a column not + * in the SELECT, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOrderByUnrelated() throws SQLException; + + /** + * Determine whether outer join operations are supported. + * + * @return <code>true</code> if outer join operations are supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsOuterJoins() throws SQLException; + + /** + * Determine whether positioned DELETE statements are supported. + * + * @return <code>true</code> if the database supports positioned DELETE + * statements. + * @throws SQLException + * a database error occurred + */ + public boolean supportsPositionedDelete() throws SQLException; + + /** + * Determine whether positioned UPDATE statements are supported. + * + * @return <code>true</code> if the database supports positioned UPDATE + * statements, <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsPositionedUpdate() throws SQLException; + + /** + * Determine whether there is support for a given concurrency style for the + * given ResultSet. + * + * @param type + * the ResultSet type, as defined in + * <code>java.sql.ResultSet</code>: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @param concurrency + * a concurrency type, which may be one of + * <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @return <code>true</code> if that concurrency and ResultSet type + * pairing is supported otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsResultSetConcurrency(int type, int concurrency) + throws SQLException; + + /** + * Determine whether the supplied ResultSet holdability is supported. + * + * @param holdability + * as specified in java.sql.ResultSet: + * ResultSet.HOLD_CURSORS_OVER_COMMIT or + * ResultSet.CLOSE_CURSORS_AT_COMMIT + * @return <code>true</code> if the given ResultSet holdability is + * supported and if it isn't then <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsResultSetHoldability(int holdability) + throws SQLException; + + /** + * Determine whether the supplied ResultSet type is supported. + * + * @param type + * the ResultSet type as defined in java.sql.ResultSet: + * <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> if the ResultSet type is supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsResultSetType(int type) throws SQLException; + + /** + * Determine whether Savepoints for transactions are supported. + * + * @return <code>true</code> if Savepoints are supported, + * <code>false</code> otherwise. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSavepoints() throws SQLException; + + /** + * Determine whether a schema name may be used in a data manipulation + * statement. + * + * @return <code>true</code> if a schema name can be used in a data + * manipulation otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSchemasInDataManipulation() throws SQLException; + + /** + * Determine whether a schema name may be used in an index definition + * statement. + * + * @return <code>true</code> if a schema name can be used in an index + * definition otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSchemasInIndexDefinitions() throws SQLException; + + /** + * Determine whether a database schema name can be used in a privilege + * definition statement. + * + * @return <code>true</code> if a database schema name may be used in a + * privilege definition otherwise <code>false</code> + * @throws SQLException + * a database error occurred + */ + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException; + + /** + * Determine if a procedure call statement may be contain in a schema name. + * + * @return <code>true</code> if a schema name can be used in a procedure + * call otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSchemasInProcedureCalls() throws SQLException; + + /** + * Determine if a schema name can be used in a table definition statement. + * + * @return <code>true</code> if a schema name can be used in a table + * definition otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSchemasInTableDefinitions() throws SQLException; + + /** + * Determine if this <code>SELECT FOR UPDATE</code> statements ar + * supported. + * + * @return <code>true</code> if <code>SELECT FOR UPDATE</code> + * statements are supported otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSelectForUpdate() throws SQLException; + + /** + * Determine whether statement pooling is supported. + * + * @return <code>true</code> of the database does support statement + * pooling otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsStatementPooling() throws SQLException; + + /** + * Determine whether stored procedure calls using the stored procedure + * escape syntax is supported. + * + * @return <code>true</code> if stored procedure calls using the stored + * procedure escape syntax are supported otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsStoredProcedures() throws SQLException; + + /** + * Determine whether subqueries in comparison expressions are supported. + * + * @return <code>true</code> if subqueries are supported in comparison + * expressions. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSubqueriesInComparisons() throws SQLException; + + /** + * Determine whether subqueries in EXISTS expressions are supported. + * + * @return <code>true</code> if subqueries are supported in EXISTS + * expressions otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSubqueriesInExists() throws SQLException; + + /** + * Determine whether subqueries in <code>IN</code> statements are + * supported. + * + * @return <code>true</code> if subqueries are supported in IN statements + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSubqueriesInIns() throws SQLException; + + /** + * Determine whether subqueries in quantified expressions are supported. + * + * @return <code>true</code> if subqueries are supported otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsSubqueriesInQuantifieds() throws SQLException; + + /** + * Determine whether the database has table correlation names support. + * + * @return <code>true</code> if table correlation names are supported + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsTableCorrelationNames() throws SQLException; + + /** + * Determine whether a specified transaction isolation level is supported. + * + * @param level + * the transaction isolation level, as specified in + * <code>java.sql.Connection</code>: + * <code>TRANSACTION_NONE</code>, + * <code>TRANSACTION_READ_COMMITTED</code>, + * <code>TRANSACTION_READ_UNCOMMITTED</code>, + * <code>TRANSACTION_REPEATABLE_READ</code>, + * <code>TRANSACTION_SERIALIZABLE</code> + * @return <code>true</code> if the specific isolation level is supported + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsTransactionIsolationLevel(int level) + throws SQLException; + + /** + * Determine whether transactions are supported. + * <p> + * If transactions are not supported, then the <code>commit</code> method + * does nothing and the transaction isolation level is always + * <code>TRANSACTION_NONE</code>. + * + * @return <code>true</code> if transactions are supported otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsTransactions() throws SQLException; + + /** + * Determine whether the <code>SQL UNION</code> operation is supported. + * + * @return <code>true</code> of the database does support + * <code>UNION</code> otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsUnion() throws SQLException; + + /** + * Determine whether the <code>SQL UNION ALL</code> operation is + * supported. + * + * @return <code>true</code> if the database does support UNION ALL + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean supportsUnionAll() throws SQLException; + + /** + * Determine if the method <code>ResultSet.rowUpdated</code> can detect a + * visible row update. + * + * @param type + * ResultSet type: <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or + * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> + * @return <code>true</code> detecting changes is possible otherwise + * <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean updatesAreDetected(int type) throws SQLException; + + /** + * Determine if this database uses a file for each table. + * + * @return <code>true</code> if the database uses one file for each table + * otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean usesLocalFilePerTable() throws SQLException; + + /** + * Determine whether this database uses a local file to store tables. + * + * @return <code>true</code> of the database does store tables in a local + * file otherwise <code>false</code>. + * @throws SQLException + * a database error occurred + */ + public boolean usesLocalFiles() throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Date.java b/sql/src/main/java/java/sql/Date.java new file mode 100644 index 0000000..ce31b01 --- /dev/null +++ b/sql/src/main/java/java/sql/Date.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.text.SimpleDateFormat; + +/** + * A Date class which can consume and produce dates in SQL Date format. + * <p> + * The SQL date format represents a date as yyyy-mm-dd. Note that this date + * format only deals with year, month and day values. There are no values for + * hours, minutes, seconds. + * <p> + * This contrasts with regular java.util.Date values, which include time values + * for hours, minutes, seconds, milliseconds. + * <p> + * Time points are handled as millisecond values - milliseconds since the epoch, + * January 1st 1970, 00:00:00.000 GMT. Time values passed to the java.sql.Date + * class are "normalized" to the time 00:00:00.000 GMT on the date implied by + * the time value. + */ +public class Date extends java.util.Date { + + private static final long serialVersionUID = 1511598038487230103L; + + /** + * @deprecated Please use the constructor {@link #Date(long)} Constructs a Date + * object corresponding to the supplied Year, Month and Day. + * @param theYear + * the year, specified as the year minus 1900. Must be in the + * range 0 to 8099. + * @param theMonth + * the month, specified as a number with 0 = January. Must be in + * the range 0 to 11. + * @param theDay + * the day in the month. Must be in the range 1 to 31. + */ + @SuppressWarnings("deprecation") + @Deprecated + public Date(int theYear, int theMonth, int theDay) { + super(theYear, theMonth, theDay); + } + + /** + * Creates a Date which corresponds to the day implied by the supplied + * theDate milliseconds time value. + * + * @param theDate - + * a time value in milliseconds since the epoch - January 1 1970 + * 00:00:00 GMT. The time value (hours, minutes, seconds, + * milliseconds) stored in the Date object is adjusted to + * correspond to 00:00:00 GMT on the day implied by the supplied + * time value. + */ + public Date(long theDate) { + super(normalizeTime(theDate)); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have an hours component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getHours() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have a minutes component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getMinutes() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have a seconds component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getSeconds() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have an hours component. + * @param theHours + * the number of hours to set + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setHours(int theHours) { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have a minutes component. + * @param theMinutes + * the number of minutes to set + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setMinutes(int theMinutes) { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. SQL Date + * values do not have a seconds component. + * @param theSeconds + * the number of seconds to set + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setSeconds(int theSeconds) { + throw new IllegalArgumentException(); + } + + /** + * Sets this date to a date supplied as a milliseconds value. The date is + * set based on the supplied time value after removing any time elements + * finer than a day, based on zero GMT for that day. + * + * @param theTime + * the time in milliseconds since the Epoch + */ + @Override + public void setTime(long theTime) { + /* + * Store the Date based on the supplied time after removing any time + * elements finer than the day based on zero GMT + */ + super.setTime(normalizeTime(theTime)); + } + + /** + * Produces a string representation of the Date in SQL format + * + * @return a string representation of the Date in SQL format - "yyyy-mm-dd". + */ + @Override + public String toString() { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ + return dateFormat.format(this); + } + + /** + * Creates a Date from a string representation of a date in SQL format. + * + * @param dateString + * the string representation of a date in SQL format - + * "yyyy-mm-dd". + * @return the Date object + * @throws IllegalArgumentException + * if the format of the supplied string does not match the SQL + * format. + */ + public static Date valueOf(String dateString) { + if (dateString == null) { + throw new IllegalArgumentException(); + } + int firstIndex = dateString.indexOf('-'); + int secondIndex = dateString.indexOf('-', firstIndex + 1); + // secondIndex == -1 means none or only one separator '-' has been + // found. + // The string is separated into three parts by two separator characters, + // if the first or the third part is null string, we should throw + // IllegalArgumentException to follow RI + if (secondIndex == -1 || firstIndex == 0 + || secondIndex + 1 == dateString.length()) { + throw new IllegalArgumentException(); + } + // parse each part of the string + int year = Integer.parseInt(dateString.substring(0, firstIndex)); + int month = Integer.parseInt(dateString.substring(firstIndex + 1, + secondIndex)); + int day = Integer.parseInt(dateString.substring(secondIndex + 1, + dateString.length())); + return new Date(year - 1900, month - 1, day); + } + + /* + * Private method which normalizes a Time value, removing all low + * significance digits corresponding to milliseconds, seconds, minutes and + * hours, so that the returned Time value corresponds to 00:00:00 GMT on a + * particular day. + */ + private static long normalizeTime(long theTime) { + return theTime; + } +} diff --git a/sql/src/main/java/java/sql/Driver.java b/sql/src/main/java/java/sql/Driver.java new file mode 100644 index 0000000..7833724 --- /dev/null +++ b/sql/src/main/java/java/sql/Driver.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Properties; + +/** + * An Interface to a JDBC Driver. + * <p> + * The JDBC Driver uses URLs to specify the location of specific data. URL + * format typically takes the form "xxxx:yyyy:SpecificData", where "xxxx:yyyy" + * is termed the subprotocol and is normally the same for all uses of a + * particular driver. "SpecificData" is a string which identifies the particular + * data source that the driver should use. + * + */ +public interface Driver { + + /** + * Returns whether the driver thinks that it can open a connection to the + * given URL. + * + * @param url + * the URL to connect to. + * @return true if the driver thinks that is can open a connection to the + * supplied URL, false otherwise. Typically, the driver will respond + * true if it thinks that it can handle the subprotocol specified by + * the driver. + * @throws SQLException + */ + public boolean acceptsURL(String url) throws SQLException; + + /** + * Attempts to make a database connection to a datasource specified by a + * supplied URL. + * + * @param url + * the url to connect. + * @param info + * some properties that should be used in establishing the + * connection. The properties consist of name/value pairs of + * Strings. Normally, a connection to a database requires at + * least two properties - for "user" and "password" in order to + * pass authentication to the database. + * @return a Connection object representing the connection to the database. + * @throws SQLException + * if a database error occurs + */ + public Connection connect(String url, Properties info) throws SQLException; + + /** + * Gets the driver's major version number. + * + * @return the major version number of the Driver - typically starts at 1. + */ + public int getMajorVersion(); + + /** + * Gets the driver's minor version number. + * + * @return the minor version number of the Driver - typically starts at 0. + */ + public int getMinorVersion(); + + /** + * Gets information about possible properties for this driver. + * <p> + * This method is intended to provide a listing of possible properties that + * the user of the driver may need to supply in order to correct connect to + * a database. Note that the returned array of Properties may change + * depending on the supplied list of property values. + * + * @param url + * the url of the database. A using program may call this method + * iteratively as the property list is built up - for example, + * when displaying a dialog to an end-user as part of the + * database login process. + * @param info + * @return an array of DriverPropertyInfo records which provide detail on + * each property that the driver will accept. + * @throws SQLException + */ + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) + throws SQLException; + + /** + * Reports whether this driver is a genuine JDBC CompliantTM driver. The + * driver may only return true from this method if it passes all the JDBC + * Compliance tests. + * <p> + * A driver may not be fully compliant if the underlying database has + * limited functionality. + * + * @return true if the driver is fully JDBC compliant, false otherwise. + */ + public boolean jdbcCompliant(); + +} diff --git a/sql/src/main/java/java/sql/DriverManager.java b/sql/src/main/java/java/sql/DriverManager.java new file mode 100644 index 0000000..78f362c --- /dev/null +++ b/sql/src/main/java/java/sql/DriverManager.java @@ -0,0 +1,433 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Properties; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Vector; +import org.apache.harmony.sql.internal.nls.Messages; +import org.apache.harmony.kernel.vm.VM; + +/** + * Provides facilities for managing JDBC Drivers. + * <p> + * The DriverManager class will load JDBC drivers during its initialization, + * from the list of drivers referenced by the System Property "jdbc.drivers". + */ +public class DriverManager { + + /* + * Facilities for logging. The Print Stream is deprecated but is maintained + * here for compatibility. + */ + private static PrintStream thePrintStream; + + private static PrintWriter thePrintWriter; + + // Login timeout value - by default set to 0 -> "wait forever" + private static int loginTimeout = 0; + + /* + * Set to hold Registered Drivers - initial capacity 10 drivers (will expand + * automatically if necessary. + */ + private static final Set<Driver> theDriverSet = new HashSet<Driver>(10); + + // Permission for setting log + private static final SQLPermission logPermission = new SQLPermission("setLog"); //$NON-NLS-1$ + + /* + * Load drivers on initialization + */ + static { + loadInitialDrivers(); + } + + /* + * Loads the set of JDBC drivers defined by the Property "jdbc.drivers" if + * it is defined. + */ + private static void loadInitialDrivers() { + String theDriverList = System.getProperty("jdbc.drivers", null); //$NON-NLS-1$ + if (theDriverList == null) { + return; + } + + /* + * Get the names of the drivers as an array of Strings from the system + * property by splitting the property at the separator character ':' + */ + String[] theDriverNames = theDriverList.split(":"); //$NON-NLS-1$ + + for (String element : theDriverNames) { + try { + // Load the driver class + Class + .forName(element, true, ClassLoader + .getSystemClassLoader()); + } catch (Throwable t) { + // Ignored + } + } + } + + /* + * A private constructor to prevent allocation + */ + private DriverManager() { + super(); + } + + /** + * Removes a driver from the DriverManager's registered driver list. This + * will only succeed where the caller's classloader loaded the driver that + * is to be removed. If the driver was loaded by a different classloader, + * the removal of the driver will fail silently. + * <p> + * If the removal succeeds, the DriverManager will not in future use this + * driver when asked to get a Connection. + * + * @param driver + * @throws SQLException + * if there is an exception accessing the database. + */ + public static void deregisterDriver(Driver driver) throws SQLException { + if (driver == null) { + return; + } +// ClassLoader callerClassLoader = VM.callerClassLoader(); //???SQL VM.callerClassLoader not implemented -> null +// +// if (!DriverManager.isClassFromClassLoader(driver, callerClassLoader)) { +// // sql.1=DriverManager: calling class not authorized to deregister JDBC driver +// throw new SecurityException(Messages.getString("sql.1")); //$NON-NLS-1$ +// } // end if + synchronized (theDriverSet) { + theDriverSet.remove(driver); + } + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with + * @return a Connection to the database identified by the URL. null if no + * connection can be made. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL + */ + public static Connection getConnection(String url) throws SQLException { + return getConnection(url, new Properties()); + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with + * @param info + * a set of Properties to use as arguments to set up the + * connection. Properties are arbitrary string/value pairs. + * Normally, at least the properties "user" and "password" should + * be passed, with appropriate settings for the userid and its + * corresponding password to get access to the database + * concerned. + * @return a Connection to the database identified by the URL. null if no + * connection can be made. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL + */ + public static Connection getConnection(String url, Properties info) + throws SQLException { + // 08 - connection exception + // 001 - SQL-client unable to establish SQL-connection + String sqlState = "08001"; //$NON-NLS-1$ + if (url == null) { + // sql.5=The url cannot be null + throw new SQLException(Messages.getString("sql.5"), sqlState); //$NON-NLS-1$ + } + synchronized (theDriverSet) { + /* + * Loop over the drivers in the DriverSet checking to see if one can + * open a connection to the supplied URL - return the first + * connection which is returned + */ + for (Driver theDriver : theDriverSet) { + Connection theConnection = theDriver.connect(url, info); + if (theConnection != null) { + return theConnection; + } + } + } + // If we get here, none of the drivers are able to resolve the URL + // sql.6=No suitable driver + throw new SQLException(Messages.getString("sql.6"), sqlState); //$NON-NLS-1$ + } + + /** + * Attempts to establish a connection to the given database URL. + * + * @param url + * a URL string representing the database target to connect with + * @param user + * a userid used to login to the database + * @param password + * a password for the userid to login to the database + * @return a Connection to the database identified by the URL. null if no + * connection can be made. + * @throws SQLException + * if there is an error while attempting to connect to the + * database identified by the URL + */ + public static Connection getConnection(String url, String user, + String password) throws SQLException { + Properties theProperties = new Properties(); + if(null != user){ + theProperties.setProperty("user", user); //$NON-NLS-1$ + } + if(null != password){ + theProperties.setProperty("password", password); //$NON-NLS-1$ + } + return getConnection(url, theProperties); + } + + /** + * Tries to find a driver that can interpret the supplied URL. + * + * @param url + * the URL of a database + * @return a Driver that can understand the given URL. null if no Driver + * understands the URL + * @throws SQLException + * if there is any kind of Database Access problem + */ + public static Driver getDriver(String url) throws SQLException { +// ClassLoader callerClassLoader = VM.callerClassLoader(); //???SQL VM.callerClassLoader not implemented -> null + + synchronized (theDriverSet) { + /* + * Loop over the drivers in the DriverSet checking to see if one + * does understand the supplied URL - return the first driver which + * does understand the URL + */ + Iterator<Driver> theIterator = theDriverSet.iterator(); + while (theIterator.hasNext()) { + Driver theDriver = theIterator.next(); + if (theDriver.acceptsURL(url) +// && DriverManager.isClassFromClassLoader(theDriver, +// callerClassLoader)) { //???SQL VM.callerClassLoader not implemented -> null + ){ + return theDriver; + } + } + } + // If no drivers understand the URL, throw an SQLException + // sql.6=No suitable driver + //SQLState: 08 - connection exception + //001 - SQL-client unable to establish SQL-connection + throw new SQLException(Messages.getString("sql.6"), "08001"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Returns an Enumeration that contains all of the loaded JDBC drivers that + * the current caller can access. + * + * @return An Enumeration containing all the currently loaded JDBC Drivers + */ + public static Enumeration<Driver> getDrivers() { +// ClassLoader callerClassLoader = VM.callerClassLoader(); //???SQL VM.callerClassLoader not implemented -> null + /* + * Synchronize to avoid clashes with additions and removals of drivers + * in the DriverSet + */ + synchronized (theDriverSet) { + /* + * Create the Enumeration by building a Vector from the elements of + * the DriverSet + */ + Vector<Driver> theVector = new Vector<Driver>(); + Iterator<Driver> theIterator = theDriverSet.iterator(); + while (theIterator.hasNext()) { + Driver theDriver = theIterator.next(); +// if (DriverManager.isClassFromClassLoader(theDriver, //???SQL VM.callerClassLoader not implemented -> null +// callerClassLoader)) { + theVector.add(theDriver); +// } + } + return theVector.elements(); + } + } + + /** + * Returns the login timeout when connecting to a database, in seconds. + * + * @return the login timeout in seconds + */ + public static int getLoginTimeout() { + return loginTimeout; + } + + /** + * @deprecated Gets the log PrintStream used by the DriverManager and all + * the JDBC Drivers. + * @return the PrintStream used for logging activity + */ + @Deprecated + public static PrintStream getLogStream() { + return thePrintStream; + } + + /** + * Retrieves the log writer. + * + * @return A PrintWriter object used as the log writer. null if no log + * writer is set. + */ + public static PrintWriter getLogWriter() { + return thePrintWriter; + } + + /** + * Prints a message to the current JDBC log stream. This is either the + * PrintWriter or (deprecated) the PrintStream, if set. + * + * @param message + * the message to print to the JDBC log stream + */ + public static void println(String message) { + if (thePrintWriter != null) { + thePrintWriter.println(message); + thePrintWriter.flush(); + } else if (thePrintStream != null) { + thePrintStream.println(message); + thePrintStream.flush(); + } + /* + * If neither the PrintWriter not the PrintStream are set, then silently + * do nothing the message is not recorded and no exception is generated. + */ + return; + } + + /** + * Registers a given JDBC driver with the DriverManager. + * <p> + * A newly loaded JDBC driver class should register itself with the + * DriverManager by calling this method. + * + * @param driver + * the Driver to register with the DriverManager + * @throws SQLException + * if a database access error occurs. + */ + public static void registerDriver(Driver driver) throws SQLException { + if (driver == null) { + throw new NullPointerException(); + } + synchronized (theDriverSet) { + theDriverSet.add(driver); + } + } + + /** + * Set the login timeout when connecting to a database, in seconds. + * + * @param seconds + * seconds until timeout. 0 indicates wait forever. + */ + public static void setLoginTimeout(int seconds) { + loginTimeout = seconds; + return; + } + + /** + * @deprecated Sets the Print Stream to use for logging data from the + * DriverManager and the JDBC drivers. + * <p> + * Use {@link #setLogWriter} instead. + * @param out + * the PrintStream to use for logging. + */ + @Deprecated + public static void setLogStream(PrintStream out) { + checkLogSecurity(); + thePrintStream = out; + } + + /** + * Sets the PrintWriter that will be used by all loaded drivers, and also + * the DriverManager. + * + * @param out + * the PrintWriter to be used + */ + public static void setLogWriter(PrintWriter out) { + checkLogSecurity(); + thePrintWriter = out; + } + + /* + * Method which checks to see if setting a logging stream is allowed by the + * Security manager + */ + private static void checkLogSecurity() { + SecurityManager securityManager = System.getSecurityManager(); + if (securityManager != null) { + // Throws a SecurityException if setting the log is not permitted + securityManager.checkPermission(logPermission); + } + } + + /** + * Finds if a supplied Object belongs to the given ClassLoader. + * + * @param theObject + * the object to check + * @param theClassLoader + * the ClassLoader + * @return true if the Object does belong to the ClassLoader, false + * otherwise + */ + private static boolean isClassFromClassLoader(Object theObject, + ClassLoader theClassLoader) { + + if ((theObject == null) || (theClassLoader == null)) { + return false; + } + + Class<?> objectClass = theObject.getClass(); + + try { + Class<?> checkClass = Class.forName(objectClass.getName(), true, + theClassLoader); + if (checkClass == objectClass) { + return true; + } + } catch (Throwable t) { + // Empty + } + return false; + } +} diff --git a/sql/src/main/java/java/sql/DriverPropertyInfo.java b/sql/src/main/java/java/sql/DriverPropertyInfo.java new file mode 100644 index 0000000..bf261db --- /dev/null +++ b/sql/src/main/java/java/sql/DriverPropertyInfo.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * A class holding information about Driver Properties for making a Connection. + * This class is returned from the <code>Driver.getDriverProperties</code> + * method and is useful in using Connections in an advanced way. + */ +public class DriverPropertyInfo { + + /** + * If the value member can be chosen from a set of possible values, they are + * contained here. Otherwise choices is null. + */ + public String[] choices; + + /** + * A description of the property. May be null. + */ + public String description; + + /** + * The name of the property. + */ + public String name; + + /** + * True when the value member must be provided during Driver.connect. False + * otherwise. + */ + public boolean required; + + /** + * The current value associated with this property. This is based on the + * data gathered by the getPropertyInfo method, the general Java environment + * and the default values for the driver. + */ + public String value; + + /** + * Creates a DriverPropertyInfo instance with the supplied name and value. + * Other members take their default values. + * + * @param name + * The property name + * @param value + * The property value + */ + public DriverPropertyInfo(String name, String value) { + this.name = name; + this.value = value; + this.choices = null; + this.description = null; + this.required = false; + } +} diff --git a/sql/src/main/java/java/sql/ParameterMetaData.java b/sql/src/main/java/java/sql/ParameterMetaData.java new file mode 100644 index 0000000..7d644d3 --- /dev/null +++ b/sql/src/main/java/java/sql/ParameterMetaData.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * An interface used to get information about the types and properties of + * parameters in a PreparedStatement object. + */ +public interface ParameterMetaData { + + /** + * Indicates that the parameter mode is IN. + */ + public static final int parameterModeIn = 1; + + /** + * Indicates that the parameter mode is INOUT. + */ + public static final int parameterModeInOut = 2; + + /** + * Indicates that the parameter mode is OUT. + */ + public static final int parameterModeOut = 4; + + /** + * Indicates that the parameter mode is not known. + */ + public static final int parameterModeUnknown = 0; + + /** + * Indicates that a parameter is not permitted to be NULL. + */ + public static final int parameterNoNulls = 0; + + /** + * Indicates that a parameter is permitted to be NULL. + */ + public static final int parameterNullable = 1; + + /** + * Indicates that whether a parameter is allowed to be null or not is not + * known. + */ + public static final int parameterNullableUnknown = 2; + + /** + * Gets the fully-qualified name of the Java class which should be passed as + * a parameter to the method <code>PreparedStatement.setObject</code>. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return a String with the fully qualified Java class name of the + * parameter with the specified index. This class name is used for + * custom mapping. + * @throws SQLException + * if a database error happens + */ + public String getParameterClassName(int paramIndex) throws SQLException; + + /** + * Gets the number of parameters in the PreparedStatement for which this + * ParameterMetaData contains information. + * + * @return the number of parameters as an int + * @throws SQLException + * if a database error happens + */ + public int getParameterCount() throws SQLException; + + /** + * Gets the mode of the specified parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return the parameters mode. Can be: ParameterMetaData.parameterModeIn, + * ParameterMetaData.parameterModeOut, + * ParameterMetaData.parameterModeInOut or + * ParameterMetaData.parameterModeUnknown. + * @throws SQLException + * if a database error happens + */ + public int getParameterMode(int paramIndex) throws SQLException; + + /** + * Gets the SQL type of a specified parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return the type of the parameter - an SQL type as defined in + * java.sql.Types. + * @throws SQLException + * if a database error happens + */ + public int getParameterType(int paramIndex) throws SQLException; + + /** + * Gets the database-specific type name of a specified parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return the type name for the parameter as used by the database. A + * fully-qualified name is returned if the parameter is a User + * Defined Type. + * @throws SQLException + * if a database error happens + */ + public String getParameterTypeName(int paramIndex) throws SQLException; + + /** + * Gets the number of decimal digits for a specified parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return the number of decimal digits ("the precision") for the parameter. + * 0 if the parameter is not a numeric type. + * @throws SQLException + * if a database error happens + */ + public int getPrecision(int paramIndex) throws SQLException; + + /** + * Gets the number of digits after the decimal point for a specified + * parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return the number of digits after the decimal point ("the scale") for + * the parameter. 0 if the parameter is not a numeric type. + * @throws SQLException + * if a database error happens + */ + public int getScale(int paramIndex) throws SQLException; + + /** + * Gets whether null values are allowed for the specified parameter. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return indicator of nullability, can be: + * ParameterMetaData.parameterNoNulls, + * ParameterMetaData.parameterNullable, or + * ParameterMetaData.parameterNullableUnknown + * @throws SQLException + * if a database error is encountered + */ + public int isNullable(int paramIndex) throws SQLException; + + /** + * Gets whether values for the specified parameter can be signed numbers. + * + * @param paramIndex + * the index number of the parameter, where the first parameter + * has an index of 1 + * @return true if values can be signed numbers for this parameter, false + * otherwise. + * @throws SQLException + * if a database error happens + */ + public boolean isSigned(int paramIndex) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/PreparedStatement.java b/sql/src/main/java/java/sql/PreparedStatement.java new file mode 100644 index 0000000..5941200 --- /dev/null +++ b/sql/src/main/java/java/sql/PreparedStatement.java @@ -0,0 +1,631 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Calendar; +import java.net.URL; +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; + +/** + * An interface for a Precompiled SQL Statement. + * <p> + * An SQL Statement is put into a PreparedStatement and is precompiled so that + * it can be executed multiple times efficiently. + * <p> + * Setter methods are supplied in the PreparedStatement interface for the + * setting of IN parameters for the Statement. The setter method used for each + * IN parameter must match the type of the IN parameter being set. + */ +public interface PreparedStatement extends Statement { + + /** + * Add a set of parameters to the PreparedStatement's command batch. + * + * @throws SQLException + * if a database error happens + */ + public void addBatch() throws SQLException; + + /** + * Clear the current parameter values. + * <p> + * Typically, parameter values are retained for multiple executions of the + * Statement. Setting a parameter value replaces the previous value. This + * method clears the values for all parameters, releasing all resources used + * by those parameters. + * + * @throws SQLException + * if a database error happens + */ + public void clearParameters() throws SQLException; + + /** + * Executes the SQL statement in this PreparedStatement. + * <p> + * A PreparedStatement may return multiple results. The execute method + * returns a flag indicating the kind of result produced by + * PreparedStatement. The methods <code> + * getResultSet</code> or + * <code>getUpdateCount</code> are used to retrieve the first result, + * while <code>getMoreResults</code> must be used to retrieve the second + * and subsequent results. + * + * @return true if the result of the execution is a ResultSet, false if + * there is no result or if the result is an update count. + * @throws SQLException + * if a database error happens + */ + public boolean execute() throws SQLException; + + /** + * Execute the SQL query in the PreparedStatement and return the ResultSet + * generated by the query. + * + * @return the ResultSet generated by the query - never null. + * @throws SQLException + * if a database error happens or if the SQL statement does not + * produce a ResultSet. + */ + public ResultSet executeQuery() throws SQLException; + + /** + * Invoke the SQL command contained within the Prepared Statement. This must + * be INSERT, UPDATE, DELETE, or a command that returns nothing. + * + * @return the count of rows for INSERT, UPDATE or DELETE statements, 0 for + * statements that return nothing + * @throws SQLException + * if a database error happens or if the SQL statement returns a + * ResultSet. + */ + public int executeUpdate() throws SQLException; + + /** + * Returns a ResultSetMetaData containing data from the ResultSet that is + * produced when the PreparedStatement is invoked. + * <p> + * It is possible to know the Metadata for the ResultSet without executing + * the PreparedStatement, because the PreparedStatement is precompiled. As a + * result the Metadata can be queried ahead of time without actually + * executing the statement. + * + * @return a ResultSetMetaData object with the information about the columns + * of the ResultSet, if the driver can return a ResultSetMetaData. + * null otherwise. + * @throws SQLException + * if there is a database error + */ + public ResultSetMetaData getMetaData() throws SQLException; + + /** + * Gets information about the parameters of the PreparedStatement. + * + * @return a ParameterMetaData object which holds information about the + * number, type and properties of the parameters of this + * PreparedStatement. + * @throws SQLException + * if a database error happens + */ + public ParameterMetaData getParameterMetaData() throws SQLException; + + /** + * Sets the value of a specified parameter to the supplied Array object. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theArray + * a java.sql.Array holing the data to set. + * @throws SQLException + * if a database error happens + */ + public void setArray(int parameterIndex, Array theArray) + throws SQLException; + + /** + * Sets the value of a specified parameter to the content of a supplied + * InputStream, which has a specified number of bytes. + * <p> + * This is a good method for setting an SQL LONVARCHAR parameter where the + * length of the data is large. Data is read from the InputStream until + * end-of-file is reached or the specified number of bytes is copied. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theInputStream + * the ASCII InputStream carrying the data to update the + * parameter + * @param length + * the number of bytes in the InputStream to copy to the + * parameter + * @throws SQLException + * if a database error happens + */ + public void setAsciiStream(int parameterIndex, InputStream theInputStream, + int length) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied + * java.math.BigDecimal value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theBigDecimal + * the java.math.BigInteger value to set + * @throws SQLException + * if a database error happens + */ + public void setBigDecimal(int parameterIndex, BigDecimal theBigDecimal) + throws SQLException; + + /** + * Sets the value of a specified parameter to the content of a supplied + * binary InputStream, which has a specified number of bytes. + * <p> + * Use this method when a large amount of data needs to be set into a + * LONGVARBINARY parameter. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theInputStream + * the binary InputStream carrying the data to update the + * parameter + * @param length + * the number of bytes in the InputStream to copy to the + * parameter + * @throws SQLException + * if a database error happens + */ + public void setBinaryStream(int parameterIndex, InputStream theInputStream, + int length) throws SQLException; + + /** + * Sets the value of a specified parameter to the given Blob object. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theBlob + * a java.sql.Blob holding the data to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setBlob(int parameterIndex, Blob theBlob) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied boolean value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theBoolean + * the boolean value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setBoolean(int parameterIndex, boolean theBoolean) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied byte value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theByte + * the byte value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setByte(int parameterIndex, byte theByte) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied array of bytes. The + * array is mapped to a VARBINARY or LONGVARBINARY in the database. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theBytes + * the array of bytes to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setBytes(int parameterIndex, byte[] theBytes) + throws SQLException; + + /** + * Sets the value of a specified parameter to the character content of a + * Reader object, with the specified length of character data. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param reader + * the java.io.Reader encompassing the character data + * @param length + * the amount of characters to be read + * @throws SQLException + * if a database error happens + */ + public void setCharacterStream(int parameterIndex, Reader reader, int length) + throws SQLException; + + /** + * Sets the value of a specified parameter to the given Clob object. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theClob + * a java.sql.Clob holding the data to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setClob(int parameterIndex, Clob theClob) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Date + * value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theDate + * a java.sql.Date to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setDate(int parameterIndex, Date theDate) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Date + * value, using a supplied Calendar to map the Date. The Calendar allows the + * application to control the timezone used to compute the SQL DATE in the + * database - without the supplied Calendar, the driver uses the default + * timezone of the Java virtual machine. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theDate + * a java.sql.Date to update the parameter + * @param cal + * a Calendar to use to construct the SQL DATE value + * @throws SQLException + * if a database error happens + */ + public void setDate(int parameterIndex, Date theDate, Calendar cal) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied double value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theDouble + * the double value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setDouble(int parameterIndex, double theDouble) + throws SQLException; + + /** + * Sets the value of a specified parameter to to a supplied float value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theFloat + * the float value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setFloat(int parameterIndex, float theFloat) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied int value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theInt + * the int value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setInt(int parameterIndex, int theInt) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied long value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theLong + * the long value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setLong(int parameterIndex, long theLong) throws SQLException; + + /** + * Sets the value of a specified parameter to SQL NULL. Don't use this + * version of setNull for User Defined Types or for REF type parameters. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param sqlType + * the SQL Type of the parameter, as defined in java.sql.Types + * @throws SQLException + * if a database error happens + */ + public void setNull(int parameterIndex, int sqlType) throws SQLException; + + /** + * Sets the value of a specified parameter to SQL NULL. This version of + * setNull should be used for User Defined Types (UDTs) and also REF types. + * UDTs can be STRUCT, DISTINCT, JAVA_OBJECT and named array types. + * <p> + * Applications must provide the SQL Type code and also a fully qualified + * SQL Type name when supplying a NULL UDT or REF. For a UDT, the type name + * is the type name of the parameter itself, but for a REF parameter the + * type name is the type name of the referenced type. + * + * @param paramIndex + * the parameter number index, where the first parameter has + * index 1 + * @param sqlType + * the SQL Type of the parameter, as defined in java.sql.Types + * @param typeName + * the fully qualified name of a UDT or REF type - ignored if the + * parameter is not a UDT. + * @throws SQLException + * if a database error happens + */ + public void setNull(int paramIndex, int sqlType, String typeName) + throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. + * <p> + * There is a standard mapping from Java types to SQL types, defined in the + * JDBC specification. The passed object is then transformed into the + * appropriate SQL type, and then transferred to the database. setObject can + * be used to pass abstract data types unique to the database, by using a + * JDBC driver specific Java type. If the object's class implements the + * interface SQLData, the JDBC driver calls <code>SQLData.writeSQL</code> + * to write it to the SQL data stream. If the object's class implements Ref, + * Blob, Clob, Struct, or Array, the driver passes it to the database as a + * value of the corresponding SQL type. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theObject + * the Object containing the value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setObject(int parameterIndex, Object theObject) + throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. + * <p> + * The Object is converted to the given targetSqlType before it is sent to + * the database. If the object has a custom mapping (its class implements + * the interface SQLData), the JDBC driver will call the method + * SQLData.writeSQL to write it to the SQL data stream. If the object's + * class implements Ref, Blob, Clob, Struct, or Array, the driver will pass + * it to the database in the form of the relevant SQL type. + * + * @param parameterIndex + * the parameter index, where the first parameter has index 1 + * @param theObject + * the Object containing the value to update the parameter + * @param targetSqlType + * the SQL Type to send to the database, as defined in + * java.sql.Types + * @throws SQLException + * if a database error happens + */ + public void setObject(int parameterIndex, Object theObject, + int targetSqlType) throws SQLException; + + /** + * Sets the value of a specified parameter using a supplied object. + * <p> + * The Object is converted to the given targetSqlType before it is sent to + * the database. If the object has a custom mapping (its class implements + * the interface SQLData), the JDBC driver will call the method + * SQLData.writeSQL to write it to the SQL data stream. If the object's + * class implements Ref, Blob, Clob, Struct, or Array, the driver will pass + * it to the database in the form of the relevant SQL type. + * + * @param parameterIndex + * the parameter index, where the first parameter has index 1 + * @param theObject + * the Object containing the value to update the parameter + * @param targetSqlType + * the SQL Type to send to the database, as defined in + * java.sql.Types + * @param scale + * the number of digits after the decimal point - only applies to + * the types java.sql.Types.DECIMAL and java.sql.Types.NUMERIC - + * ignored for all other types. + * @throws SQLException + * if a database error happens + */ + public void setObject(int parameterIndex, Object theObject, + int targetSqlType, int scale) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied REF(<structured-type>) + * value. This is stored as an SQL REF. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theRef + * a java.sql.Ref value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setRef(int parameterIndex, Ref theRef) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied short value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theShort + * a short value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setShort(int parameterIndex, short theShort) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied String. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theString + * a String value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setString(int parameterIndex, String theString) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Time + * value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theTime + * a java.sql.Time value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setTime(int parameterIndex, Time theTime) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Time + * value, using a supplied Calendar. + * <p> + * The driver uses the supplied Calendar to create the SQL TIME value, which + * allows it to use a custom timezone - otherwise the driver uses the + * default timezone of the Java virtual machine. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theTime + * a java.sql.Time value to update the parameter + * @param cal + * a Calendar to use to construct the SQL TIME value + * @throws SQLException + * if a database error happens + */ + public void setTime(int parameterIndex, Time theTime, Calendar cal) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Timestamp + * value. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theTimestamp + * the java.sql.Timestamp value to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setTimestamp(int parameterIndex, Timestamp theTimestamp) + throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.sql.Timestamp + * value, using the supplied Calendar. + * <p> + * The driver uses the supplied Calendar to create the SQL TIMESTAMP value, + * which allows it to use a custom timezone - otherwise the driver uses the + * default timezone of the Java virtual machine. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theTimestamp + * the java.sql.Timestamp value to update the parameter + * @param cal + * a Calendar to use to construct the SQL TIMESTAMP value + * @throws SQLException + * if a database error happens + */ + public void setTimestamp(int parameterIndex, Timestamp theTimestamp, + Calendar cal) throws SQLException; + + /** + * @deprecated Sets the value of a specified parameter to the characters + * from a supplied InputStream, with a specified number of + * bytes. + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theInputStream + * the InputStream with the character data to update the + * parameter + * @param length + * the number of bytes to read from the InputStream + * @throws SQLException + * if a database error happens + */ + @Deprecated + public void setUnicodeStream(int parameterIndex, + InputStream theInputStream, int length) throws SQLException; + + /** + * Sets the value of a specified parameter to a supplied java.net.URL. + * + * @param parameterIndex + * the parameter number index, where the first parameter has + * index 1 + * @param theURL + * the URL to update the parameter + * @throws SQLException + * if a database error happens + */ + public void setURL(int parameterIndex, URL theURL) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Ref.java b/sql/src/main/java/java/sql/Ref.java new file mode 100644 index 0000000..cc0adf4 --- /dev/null +++ b/sql/src/main/java/java/sql/Ref.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Map; + +/** + * A manifestation of the SQL REF type - a reference to an SQL type contained in + * the database. + * <p> + * The SQL REF's are held in a table along with SQL structured types. Every REF + * has an individual identifier for each single instance. The SQL REF is used + * instead of the structured type it references. + * <p> + * A Ref object is stored into the database using the PreparedStatement.setRef + * method. + */ +public interface Ref { + + /** + * Gets the fully-qualified SQL name of the SQL structured type that this + * Ref references. + * + * @return the fully qualified name of the SQL structured type + * @throws SQLException + * if there is a database error + */ + public String getBaseTypeName() throws SQLException; + + /** + * Gets the SQL structured type instance referenced by this Ref. + * + * @return a Java object whose type is defined by the mapping for the SQL + * structured type. + * @throws SQLException + * if there is a database error + */ + public Object getObject() throws SQLException; + + /** + * Returns the associated object and uses the relevant mapping to convert it + * to a Java type. + * + * @param map + * a java.util.Map which contains the mapping to use + * @return a Java object whose type is defined by the mapping for the SQL + * structured type. + * @throws SQLException + * if there is a database error + */ + public Object getObject(Map<String, Class<?>> map) throws SQLException; + + /** + * Sets the value of the structured typethat this Ref references to a + * supplied Object. + * + * @param value + * the Object representing the new SQL structured type that this + * Ref will reference. + * @throws SQLException + * if there is a database error + */ + public void setObject(Object value) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/ResultSet.java b/sql/src/main/java/java/sql/ResultSet.java new file mode 100644 index 0000000..dd2334e --- /dev/null +++ b/sql/src/main/java/java/sql/ResultSet.java @@ -0,0 +1,1870 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.io.Reader; +import java.util.Calendar; +import java.util.Map; +import java.net.URL; + +/** + * An interface to an Object which represents a Table of Data, typically + * returned as the result of a Query to a Database. + * <p> + * <code>ResultSets</code> have a Cursor which points to a current row of + * data. When a ResultSet is created, the Cursor is positioned before the first + * row. To move the Cursor to the next row in the table, use the + * <code>next</code> method. The next method returns true until there are no + * more rows in the ResultSet, when it returns false. + * <p> + * The default type of ResultSet cannot be updated and its cursor can only move + * forward through the rows of data. This means that it is only possible to read + * through it once. However, it is possible to create types of ResultSet that + * can be updated and also types where the cursor can be scrolled forward and + * backward through the rows of data. This is shown in the following code + * example: <code> + * Connection con; + * Statement aStatement = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, + * ResultSet.CONCUR_UPDATABLE ); + * ResultSet theResultSet = theStatement.executeQuery("SELECT price, quantity FROM STOCKTABLE"); + * // theResultSet will be both scrollable and updateable + * </code> + * <p> + * The ResultSet interface provides a series of methods for retrieving data from + * columns in the current row, such as getDate, getFloat. The columns are + * identified either by their index number (starting at 1) or by their name - + * there are separate methods for both techniques of column addressing. The + * column names are case insensitive. If several columns have the same name, + * then the getter methods use the first matching column. This means that if + * column names are used, it is not possible to guarantee that the name will + * retrieve data from the intended column - for certainty it is better to use + * column indexes. Ideally the columns should be read left-to-right and read + * once only, since not all * databases are optimized to handle other techniques + * of reading the data. + * <p> + * When reading data, the JDBC driver maps the SQL data retrieved from the + * database to the Java type implied by the method invoked by the application. + * The JDBC specification has a table of allowable mappings from SQL types to + * Java types. + * <p> + * There are also methods for writing data into the ResultSet, such as + * updateInt, updateString. The update methods can be used either to modify the + * data of an existing row or to insert new data rows into the ResultSet. + * Modification of existing data involves moving the Cursor to the row which + * needs modification and then using the update methods to modify the data, + * followed by calling the ResultSet.updateRow method. For insertion of new + * rows, the cursor is first moved to a special row called the Insert Row, data + * is added using the update methods, followed by calling the + * ResultSet.insertRow method. + * <p> + * A ResultSet is closed if the Statement object which generated it closed, + * executed again or is used to retrieve the next result from a sequence of + * results. + * + */ +public interface ResultSet { + + /** + * A constant used to indicate that a ResultSet object must be closed when + * the method Connection.commit is invoked. + */ + public static final int CLOSE_CURSORS_AT_COMMIT = 2; + + /** + * A constant used to indicate that a ResultSet object must not be closed + * when the method Connection.commit is invoked. + */ + public static final int HOLD_CURSORS_OVER_COMMIT = 1; + + /** + * A constant used to indicate the Concurrency Mode for a ResultSet object + * that cannot be updated. + */ + public static final int CONCUR_READ_ONLY = 1007; + + /** + * A constant used to indicate the Concurrency Mode for a ResultSet object + * that can be updated. + */ + public static final int CONCUR_UPDATABLE = 1008; + + /** + * A constant used to indicate processing of the rows of a ResultSet in the + * forward direction, first to last + */ + public static final int FETCH_FORWARD = 1000; + + /** + * A constant used to indicate processing of the rows of a ResultSet in the + * reverse direction, last to first + */ + public static final int FETCH_REVERSE = 1001; + + /** + * A constant used to indicate that the order of processing of the rows of a + * ResultSet is unknown. + */ + public static final int FETCH_UNKNOWN = 1002; + + /** + * A constant used to indicate a ResultSet object whose Cursor can only move + * forward + */ + public static final int TYPE_FORWARD_ONLY = 1003; + + /** + * A constant used to indicate a ResultSet object which is Scrollable but + * which is not sensitive to changes made by others + */ + public static final int TYPE_SCROLL_INSENSITIVE = 1004; + + /** + * A constant used to indicate a ResultSet object which is Scrollable but + * which is sensitive to changes made by others + */ + public static final int TYPE_SCROLL_SENSITIVE = 1005; + + /** + * Moves the Cursor to a specified row number in the ResultSet. + * + * @param row + * The new row number for the Cursor + * @return true if the new Cursor position is on the ResultSet, false + * otherwise + * @throws SQLException + * if a database error happens + */ + public boolean absolute(int row) throws SQLException; + + /** + * Moves the Cursor to the end of the ResultSet, after the last row. + * + * @throws SQLException + * if a database error happens + */ + public void afterLast() throws SQLException; + + /** + * Moves the Cursor to the start of the ResultSet, before the first row. + * + * @throws SQLException + * if a database error happens + */ + public void beforeFirst() throws SQLException; + + /** + * Cancels any updates made to the current row in the ResultSet. + * + * @throws SQLException + * if a database error happens + */ + public void cancelRowUpdates() throws SQLException; + + /** + * Clears all the warnings related to this ResultSet. + * + * @throws SQLException + * if a database error happens + */ + public void clearWarnings() throws SQLException; + + /** + * Releases this ResultSet's database and JDBC resources. You are strongly + * advised to use this method rather than relying on the release being done + * when the ResultSet's finalize method is called during garbage collection + * process. Note that the close() method might take some time to complete + * since it is dependent on the behaviour of the connection to the database + * and the database itself. + * + * @throws SQLException + * if a database error happens + */ + public void close() throws SQLException; + + /** + * Deletes the current row from the ResultSet and from the underlying + * database. + * + * @throws SQLException + * if a database error happens + */ + public void deleteRow() throws SQLException; + + /** + * Gets the index number for a column in the ResultSet from the provided + * Column Name. + * + * @param columnName + * the column name + * @return the index of the column in the ResultSet for the column name + * @throws SQLException + * if a database error happens + */ + public int findColumn(String columnName) throws SQLException; + + /** + * Shifts the cursor position to the first row in the ResultSet. + * + * @return true if the position is in a legitimate row, false if the + * ResultSet contains no rows. + * @throws SQLException + * if a database error happens + */ + public boolean first() throws SQLException; + + /** + * Gets the content of a column specified as a column index in the current + * row of this ResultSet as a java.sql.Array. + * + * @param columnIndex + * the index of the column to read + * @return a java.sql.Array with the data from the column + * @throws SQLException + * if a database error happens + */ + public Array getArray(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a + * java.sql.Array. + * + * @param colName + * the name of the column to read + * @return a java.sql.Array with the data from the column + * @throws SQLException + * if a database error happens + */ + public Array getArray(String colName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as an ASCII + * character stream. + * + * @param columnIndex + * the index of the column to read + * @return an InputStream with the data from the column + * @throws SQLException + * if a database error happens + */ + public InputStream getAsciiStream(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as an ASCII + * character stream. + * + * @param columnName + * the name of the column to read + * @return an InputStream with the data from the column + * @throws SQLException + * if a database error happens + */ + public InputStream getAsciiStream(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.math.BigDecimal. + * + * @param columnIndex + * the index of the column to read + * @return a BigDecimal with the value of the column + * @throws SQLException + * if a database error happens + */ + public BigDecimal getBigDecimal(int columnIndex) throws SQLException; + + /** + * @deprecated Gets the value of a column specified as a column index as a + * java.math.BigDecimal. + * @param columnIndex + * the index of the column to read + * @param scale + * the number of digits after the decimal point + * @return a BigDecimal with the value of the column + * @throws SQLException + * if a database error happens + */ + @Deprecated + public BigDecimal getBigDecimal(int columnIndex, int scale) + throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a + * java.math.BigDecimal. + * + * @param columnName + * the name of the column to read + * @return a BigDecimal with the value of the column + * @throws SQLException + * if a database error happens + */ + public BigDecimal getBigDecimal(String columnName) throws SQLException; + + /** + * @deprecated Gets the value of a column specified as a column name, as a + * java.math.BigDecimal. + * @param columnName + * the name of the column to read + * @param scale + * the number of digits after the decimal point + * @return a BigDecimal with the value of the column + * @throws SQLException + * if a database error happens + */ + @Deprecated + public BigDecimal getBigDecimal(String columnName, int scale) + throws SQLException; + + /** + * Gets the value of a column specified as a column index as a binary + * stream. + * <p> + * This method can be used to read LONGVARBINARY values. All of the data in + * the InputStream should be read before getting data from any other column. + * A further call to a getter method will implicitly close the InputStream. + * + * @param columnIndex + * the index of the column to read + * @return an InputStream with the data from the column. If the column value + * is SQL NULL, null is returned. + * @throws SQLException + * if a database error happens + */ + public InputStream getBinaryStream(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a binary stream. + * <p> + * This method can be used to read LONGVARBINARY values. All of the data in + * the InputStream should be read before getting data from any other column. + * A further call to a getter method will implicitly close the InputStream. + * + * @param columnName + * the name of the column to read + * @return an InputStream with the data from the column If the column value + * is SQL NULL, null is returned. + * @throws SQLException + * if a database error happens + */ + public InputStream getBinaryStream(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a java.sql.Blob + * object. + * + * @param columnIndex + * the index of the column to read + * @return a java.sql.Blob with the value of the column + * @throws SQLException + * if a database error happens + */ + public Blob getBlob(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a java.sql.Blob + * object. + * + * @param columnName + * the name of the column to read + * @return a java.sql.Blob with the value of the column + * @throws SQLException + * if a database error happens + */ + public Blob getBlob(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a boolean. + * + * @param columnIndex + * the index of the column to read + * @return a boolean value from the column. If the column is SQL NULL, false + * is returned. + * @throws SQLException + * if a database error happens + */ + public boolean getBoolean(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a boolean. + * + * @param columnName + * the name of the column to read + * @return a boolean value from the column. If the column is SQL NULL, false + * is returned. + * @throws SQLException + * if a database error happens + */ + public boolean getBoolean(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a byte. + * + * @param columnIndex + * the index of the column to read + * @return a byte containing the value of the column. 0 if the value is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public byte getByte(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a byte. + * + * @param columnName + * the name of the column to read + * @return a byte containing the value of the column. 0 if the value is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public byte getByte(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a byte array. + * + * @param columnIndex + * the index of the column to read + * @return a byte array containing the value of the column. null if the + * column contains SQL NULL. + * @throws SQLException + * if a database error happens + */ + public byte[] getBytes(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a byte array. + * + * @param columnName + * the name of the column to read + * @return a byte array containing the value of the column. null if the + * column contains SQL NULL. + * @throws SQLException + * if a database error happens + */ + public byte[] getBytes(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.io.Reader object. + * + * @param columnIndex + * the index of the column to read + * @return a Reader holding the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Reader getCharacterStream(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a java.io.Reader + * object. + * + * @param columnName + * the name of the column to read + * @return a Reader holding the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Reader getCharacterStream(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.sql.Clob. + * + * @param columnIndex + * the index of the column to read + * @return a Clob object representing the value in the column. null if the + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Clob getClob(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a java.sql.Clob. + * + * @param colName + * the name of the column to read + * @return a Clob object representing the value in the column. null if the + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Clob getClob(String colName) throws SQLException; + + /** + * Gets the concurrency mode of this ResultSet. + * + * @return the concurrency mode - one of: ResultSet.CONCUR_READ_ONLY, + * ResultSet.CONCUR_UPDATABLE + * @throws SQLException + * if a database error happens + */ + public int getConcurrency() throws SQLException; + + /** + * Gets the name of the SQL cursor of this ResultSet. + * + * @return a String containing the SQL cursor name + * @throws SQLException + * if a database error happens + */ + public String getCursorName() throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.sql.Date. + * + * @param columnIndex + * the index of the column to read + * @return a java.sql.Date matching the column value. null if the column is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.sql.Date. This method uses a supplied calendar to compute the Date. + * + * @param columnIndex + * the index of the column to read + * @param cal + * a java.util.Calendar to use in constructing the Date. + * @return a java.sql.Date matching the column value. null if the column is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(int columnIndex, Calendar cal) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a java.sql.Date. + * + * @param columnName + * the name of the column to read + * @return a java.sql.Date matching the column value. null if the column is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a java.sql.Date + * object. + * + * @param columnName + * the name of the column to read + * @param cal + * java.util.Calendar to use in constructing the Date. + * @return a java.sql.Date matching the column value. null if the column is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Date getDate(String columnName, Calendar cal) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a double value. + * + * @param columnIndex + * the index of the column to read + * @return a double containing the column value. 0.0 if the column is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public double getDouble(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a double value. + * + * @param columnName + * the name of the column to read + * @return a double containing the column value. 0.0 if the column is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public double getDouble(String columnName) throws SQLException; + + /** + * Gets the direction in which rows are fetched for this ResultSet object. + * + * @return the fetch direction. Will be: ResultSet.FETCH_FORWARD, + * ResultSet.FETCH_REVERSE or ResultSet.FETCH_UNKNOWN + * @throws SQLException + * if a database error happens + */ + public int getFetchDirection() throws SQLException; + + /** + * Gets the fetch size (in number of rows) for this ResultSet + * + * @return the fetch size as an int + * @throws SQLException + * if a database error happens + */ + public int getFetchSize() throws SQLException; + + /** + * Gets the value of a column specified as a column index as a float value. + * + * @param columnIndex + * the index of the column to read + * @return a float containing the column value. 0.0 if the column is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public float getFloat(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a float value. + * + * @param columnName + * the name of the column to read + * @return a float containing the column value. 0.0 if the column is SQL + * NULL. + * @throws SQLException + * if a database error happens + */ + public float getFloat(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as an int value. + * + * @param columnIndex + * the index of the column to read + * @return an int containing the column value. 0 if the column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public int getInt(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as an int value. + * + * @param columnName + * the name of the column to read + * @return an int containing the column value. 0 if the column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public int getInt(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a long value. + * + * @param columnIndex + * the index of the column to read + * @return a long containing the column value. 0 if the column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public long getLong(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a long value. + * + * @param columnName + * the name of the column to read + * @return a long containing the column value. 0 if the column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public long getLong(String columnName) throws SQLException; + + /** + * Gets the Metadata for this ResultSet. This defines the number, types and + * properties of the columns in the ResultSet. + * + * @return a ResultSetMetaData object with information about this ResultSet. + * @throws SQLException + * if a database error happens + */ + public ResultSetMetaData getMetaData() throws SQLException; + + /** + * Gets the value of a specified column as a Java Object. The type of the + * returned object will be the default according to the column's SQL type, + * following the JDBC specification for built-in types. + * <p> + * For SQL User Defined Types, if a column value is Structured or Distinct, + * this method behaves the same as a call to: getObject(columnIndex, + * this.getStatement().getConnection().getTypeMap()) + * + * @param columnIndex + * the index of the column to read + * @return an Object containing the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Object getObject(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a Java Object. + * <p> + * The type of the Java object will be determined by the supplied Map to + * perform the mapping of SQL Struct or Distinct types into Java objects. + * + * @param columnIndex + * the index of the column to read + * @param map + * a java.util.Map containing a mapping from SQL Type names to + * Java classes. + * @return an Object containing the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Object getObject(int columnIndex, Map<String, Class<?>> map) + throws SQLException; + + /** + * Gets the value of a specified column as a Java Object. The type of the + * returned object will be the default according to the column's SQL type, + * following the JDBC specification for built-in types. + * <p> + * For SQL User Defined Types, if a column value is Structured or Distinct, + * this method behaves the same as a call to: getObject(columnIndex, + * this.getStatement().getConnection().getTypeMap()) + * + * @param columnName + * the name of the column to read + * @return an Object containing the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Object getObject(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a Java Object. + * <p> + * The type of the Java object will be determined by the supplied Map to + * perform the mapping of SQL Struct or Distinct types into Java objects. + * + * @param columnName + * the name of the column to read + * @param map + * a java.util.Map containing a mapping from SQL Type names to + * Java classes. + * @return an Object containing the value of the column. null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Object getObject(String columnName, Map<String, Class<?>> map) + throws SQLException; + + /** + * Gets the value of a column specified as a column index as a Java + * java.sql.Ref. + * + * @param columnIndex + * the index of the column to read + * @return a Ref representing the value of the SQL REF in the column + * @throws SQLException + * if a database error happens + */ + public Ref getRef(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a Java + * java.sql.Ref. + * + * @param colName + * the name of the column to read + * @return a Ref representing the value of the SQL REF in the column + * @throws SQLException + * if a database error happens + */ + public Ref getRef(String colName) throws SQLException; + + /** + * Gets the number of the current row in the ResultSet. Row numbers start at + * 1 for the first row. + * + * @return the index number of the current row. 0 is returned if there is no + * current row. + * @throws SQLException + * if a database error happens + */ + public int getRow() throws SQLException; + + /** + * Gets the value of a column specified as a column index as a short value. + * + * @param columnIndex + * the index of the column to read + * @return a short value containing the value of the column. 0 if the value + * is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public short getShort(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a short value. + * + * @param columnName + * the name of the column to read + * @return a short value containing the value of the column. 0 if the value + * is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public short getShort(String columnName) throws SQLException; + + /** + * Gets the Statement that produced this ResultSet. If the ResultSet was not + * created by a Statement (eg it was returned from one of the + * DatabaseMetaData methods), null is returned. + * + * @return the Statement which produced this ResultSet, or null if the + * ResultSet was not created by a Statement. + * @throws SQLException + */ + public Statement getStatement() throws SQLException; + + /** + * Gets the value of a column specified as a column index as a String. + * + * @param columnIndex + * the index of the column to read + * @return the String representing the value of the column, null if the + * column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public String getString(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a String. + * + * @param columnName + * the name of the column to read + * @return the String representing the value of the column, null if the + * column is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public String getString(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a java.sql.Time + * value. + * + * @param columnIndex + * the index of the column to read + * @return a Time representing the column value, null if the column value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a java.sql.Time + * value. The supplied Calendar is used to map between the SQL Time value + * and the Java Time value. + * + * @param columnIndex + * the index of the column to read + * @param cal + * a Calendar to use in creating the Java Time value. + * @return a Time representing the column value, null if the column value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(int columnIndex, Calendar cal) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a java.sql.Time + * value. + * + * @param columnName + * the name of the column to read + * @return a Time representing the column value, null if the column value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index, as a + * java.sql.Time value. The supplied Calendar is used to map between the SQL + * Time value and the Java Time value. + * + * @param columnName + * the name of the column to read + * @param cal + * a Calendar to use in creating the Java Time value. + * @return a Time representing the column value, null if the column value is + * SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Time getTime(String columnName, Calendar cal) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a + * java.sql.Timestamp value. + * + * @param columnIndex + * the index of the column to read + * @return a Timestamp representing the column value, null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column index, as a + * java.sql.Timestamp value. The supplied Calendar is used to map between + * the SQL Timestamp value and the Java Timestamp value. + * + * @param columnIndex + * the index of the column to read + * @param cal + * Calendar to use in creating the Java Timestamp value. + * @return a Timestamp representing the column value, null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(int columnIndex, Calendar cal) + throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a + * java.sql.Timestamp value. + * + * @param columnName + * the name of the column to read + * @return a Timestamp representing the column value, null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column name, as a + * java.sql.Timestamp value. The supplied Calendar is used to map between + * the SQL Timestamp value and the Java Timestamp value. + * + * @param columnName + * the name of the column to read + * @param cal + * Calendar to use in creating the Java Timestamp value. + * @return a Timestamp representing the column value, null if the column + * value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public Timestamp getTimestamp(String columnName, Calendar cal) + throws SQLException; + + /** + * Gets the type of the ResultSet. + * + * @return The ResultSet type, one of: ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.TYPE_SCROLL_INSENSITIVE, or + * ResultSet.TYPE_SCROLL_SENSITIVE + * @throws SQLException + * if there is a database error + */ + public int getType() throws SQLException; + + /** + * @deprecated Use {@link #getCharacterStream}. + * <p> + * Gets the value of the column as an InputStream of Unicode + * characters. + * @param columnIndex + * the index of the column to read + * @return an InputStream holding the value of the column. null if the + * column value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + @Deprecated + public InputStream getUnicodeStream(int columnIndex) throws SQLException; + + /** + * @deprecated Use {@link #getCharacterStream} + * <p> + * Gets the value of the column as an InputStream of Unicode + * characters. + * @param columnName + * the name of the column to read + * @return an InputStream holding the value of the column. null if the + * column value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + @Deprecated + public InputStream getUnicodeStream(String columnName) throws SQLException; + + /** + * Gets the value of a column specified as a column index as a java.net.URL. + * + * @param columnIndex + * the index of the column to read + * @return a URL. null if the column value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public URL getURL(int columnIndex) throws SQLException; + + /** + * Gets the value of a column specified as a column name as a java.net.URL + * object. + * + * @param columnName + * the name of the column to read + * @return a URL. null if the column value is SQL NULL. + * @throws SQLException + * if a database error happens + */ + public URL getURL(String columnName) throws SQLException; + + /** + * Gets the first warning generated by calls on this ResultSet. Subsequent + * warnings on this ResultSet are chained to the first one. + * <p> + * The warnings are cleared when a new Row is read from the ResultSet. The + * warnings returned by this method are only the warnings generated by + * ResultSet method calls - warnings generated by Statement methods are held + * by the Statement. + * <p> + * An SQLException is generated if this method is called on a closed + * ResultSet. + * + * @return an SQLWarning which is the first warning for this ResultSet. null + * if there are no warnings. + * @throws SQLException + * if a database error happens + */ + public SQLWarning getWarnings() throws SQLException; + + /** + * Insert the insert row into the ResultSet and into the underlying + * database. The Cursor must be set to the Insert Row before this method is + * invoked. + * + * @throws SQLException + * if a database error happens. Particular cases include the + * Cursor not being on the Insert Row or if any Columns in the + * Row do not have a value where the column is declared as + * not-nullable. + */ + public void insertRow() throws SQLException; + + /** + * Gets if the cursor is after the last row of the ResultSet. + * + * @return true if the Cursor is after the last Row in the ResultSet, false + * if the cursor is at any other position in the ResultSet. + * @throws SQLException + * if a database error happens + */ + public boolean isAfterLast() throws SQLException; + + /** + * Gets if the cursor is before the first row of the ResultSet. + * + * @return true if the Cursor is before the last Row in the ResultSet, false + * if the cursor is at any other position in the ResultSet. + * @throws SQLException + * if a database error happens + */ + public boolean isBeforeFirst() throws SQLException; + + /** + * Gets if the cursor is on the first row of the ResultSet. + * + * @return true if the Cursor is on the first Row in the ResultSet, false if + * the cursor is at any other position in the ResultSet. + * @throws SQLException + * if a database error happens + */ + public boolean isFirst() throws SQLException; + + /** + * Gets if the cursor is on the last row of the ResultSet + * + * @return true if the Cursor is on the last Row in the ResultSet, false if + * the cursor is at any other position in the ResultSet. + * @throws SQLException + */ + public boolean isLast() throws SQLException; + + /** + * Shifts the cursor position to the last row of the ResultSet. + * + * @return true if the new position is in a legitimate row, false if the + * ResultSet contains no rows. + * @throws SQLException + * if there is a database error + */ + public boolean last() throws SQLException; + + /** + * Moves the cursor to the remembered position, usually the current row. + * This only applies if the cursor is on the Insert row. + * + * @throws SQLException + * if a database error happens + */ + public void moveToCurrentRow() throws SQLException; + + /** + * Moves the cursor position to the Insert row. The current position is + * remembered and the cursor is positioned at the Insert row. The columns in + * the Insert row should be filled in with the appropriate update methods, + * before calling <code>insertRow</code> to insert the new row into the + * database. + * + * @throws SQLException + * if a database error happens + */ + public void moveToInsertRow() throws SQLException; + + /** + * Shifts the cursor position down one row in this ResultSet object. + * <p> + * Any InputStreams associated with the current row are closed and any + * warnings are cleared. + * + * @return true if the updated cursor position is pointing to a valid row, + * false otherwise (ie when the cursor is after the last row in the + * ResultSet). + * @throws SQLException + * if a database error happens + */ + public boolean next() throws SQLException; + + /** + * Relocates the cursor position to the preceding row in this ResultSet. + * + * @return true if the new position is in a legitimate row, false if the + * cursor is now before the first row. + * @throws SQLException + * if a database error happens + */ + public boolean previous() throws SQLException; + + /** + * Refreshes the current row with its most up to date value in the database. + * Must not be called when the cursor is on the Insert row. + * <p> + * If any columns in the current row have been updated but the + * <code>updateRow</code> has not been called, then the updates are lost + * when this method is called. + * + * @throws SQLException + * if a database error happens, including if the current row is + * the Insert row. + */ + public void refreshRow() throws SQLException; + + /** + * Moves the cursor position up or down by a specified number of rows. If + * the new position is beyond the start or end rows, the cursor position is + * set before the first row/after the last row. + * + * @param rows + * a number of rows to move the cursor - may be positive or + * negative + * @return true if the new cursor position is on a row, false otherwise + * @throws SQLException + * if a database error happens + */ + public boolean relative(int rows) throws SQLException; + + /** + * Indicates whether a row has been deleted. This method depends on whether + * the JDBC driver and database can detect deletions. + * + * @return true if a row has been deleted and if deletions are detected, + * false otherwise. + * @throws SQLException + * if a database error happens + */ + public boolean rowDeleted() throws SQLException; + + /** + * Indicates whether the current row has had an insertion operation. This + * method depends on whether the JDBC driver and database can detect + * insertions. + * + * @return true if a row has been inserted and if insertions are detected, + * false otherwise. + * @throws SQLException + * if a database error happens + */ + public boolean rowInserted() throws SQLException; + + /** + * Indicates whether the current row has been updated. This method depends + * on whether the JDBC driver and database can detect updates. + * + * @return true if the current row has been updated and if updates can be + * detected, false otherwise. + * @throws SQLException + * if a database error happens + */ + public boolean rowUpdated() throws SQLException; + + /** + * Indicates which direction (forward/reverse) will be used to process the + * rows of this ResultSet object. This is treated as a hint by the JDBC + * driver. + * + * @param direction + * can be ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, or + * ResultSet.FETCH_UNKNOWN + * @throws SQLException + * if there is a database error + */ + public void setFetchDirection(int direction) throws SQLException; + + /** + * Indicates the amount of rows to fetch from the database when extra rows + * are required for this ResultSet. This used as a hint to the JDBC driver. + * + * @param rows + * the number of rows to fetch. 0 implies that the JDBC driver + * can make its own decision about the fetch size. The number + * should not be greater than the maximum number of rows + * established by the Statement that generated the ResultSet. + * @throws SQLException + * if a database error happens + */ + public void setFetchSize(int rows) throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.Array value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateArray(int columnIndex, Array x) throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.Array value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateArray(String columnName, Array x) throws SQLException; + + /** + * Updates a column specified by a column index with an ASCII stream value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @param length + * the length of the data to write from the stream + * @throws SQLException + * if a database error happens + */ + public void updateAsciiStream(int columnIndex, InputStream x, int length) + throws SQLException; + + /** + * Updates a column specified by a column name with an Ascii stream value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @param length + * the length of the data to write from the stream + * @throws SQLException + * if a database error happens + */ + public void updateAsciiStream(String columnName, InputStream x, int length) + throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.BigDecimal + * value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBigDecimal(int columnIndex, BigDecimal x) + throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.BigDecimal + * value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBigDecimal(String columnName, BigDecimal x) + throws SQLException; + + /** + * Updates a column specified by a column index with a binary stream value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @param length + * @throws SQLException + * if a database error happens + */ + public void updateBinaryStream(int columnIndex, InputStream x, int length) + throws SQLException; + + /** + * Updates a column specified by a column name with a binary stream value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @param length + * @throws SQLException + * if a database error happens + */ + public void updateBinaryStream(String columnName, InputStream x, int length) + throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.Blob value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBlob(int columnIndex, Blob x) throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.Blob value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBlob(String columnName, Blob x) throws SQLException; + + /** + * Updates a column specified by a column index with a boolean value. + * + * @param columnIndex + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBoolean(int columnIndex, boolean x) throws SQLException; + + /** + * Updates a column specified by a column name with a boolean value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBoolean(String columnName, boolean x) throws SQLException; + + /** + * Updates a column specified by a column index with a byte value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateByte(int columnIndex, byte x) throws SQLException; + + /** + * Updates a column specified by a column name with a byte value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateByte(String columnName, byte x) throws SQLException; + + /** + * Updates a column specified by a column index with a byte array value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBytes(int columnIndex, byte[] x) throws SQLException; + + /** + * Updates a column specified by a column name with a byte array value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateBytes(String columnName, byte[] x) throws SQLException; + + /** + * Updates a column specified by a column index with a character stream + * value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @param length + * the length of data to write from the stream + * @throws SQLException + * if a database error happens + */ + public void updateCharacterStream(int columnIndex, Reader x, int length) + throws SQLException; + + /** + * Updates a column specified by a column name with a character stream + * value. + * + * @param columnName + * the name of the column to update + * @param reader + * the new value for the specified column + * @param length + * the length of data to write from the Reader + * @throws SQLException + * if a database error happens + */ + public void updateCharacterStream(String columnName, Reader reader, + int length) throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.Clob value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateClob(int columnIndex, Clob x) throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.Clob value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateClob(String columnName, Clob x) throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.Date value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateDate(int columnIndex, Date x) throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.Date value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateDate(String columnName, Date x) throws SQLException; + + /** + * Updates a column specified by a column index with a double value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateDouble(int columnIndex, double x) throws SQLException; + + /** + * Updates a column specified by a column name with a double value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateDouble(String columnName, double x) throws SQLException; + + /** + * Updates a column specified by a column index with a float value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateFloat(int columnIndex, float x) throws SQLException; + + /** + * Updates a column specified by a column name with a float value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateFloat(String columnName, float x) throws SQLException; + + /** + * Updates a column specified by a column index with an int value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateInt(int columnIndex, int x) throws SQLException; + + /** + * Updates a column specified by a column name with an int value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateInt(String columnName, int x) throws SQLException; + + /** + * Updates a column specified by a column index with a long value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateLong(int columnIndex, long x) throws SQLException; + + /** + * Updates a column specified by a column name with a long value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateLong(String columnName, long x) throws SQLException; + + /** + * Updates a column specified by a column index with a null value. + * + * @param columnIndex + * the index of the column to update + * @throws SQLException + * if a database error happens + */ + public void updateNull(int columnIndex) throws SQLException; + + /** + * Updates a column specified by a column name with a null value. + * + * @param columnName + * the name of the column to update + * @throws SQLException + * if a database error happens + */ + public void updateNull(String columnName) throws SQLException; + + /** + * Updates a column specified by a column index with an Object value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateObject(int columnIndex, Object x) throws SQLException; + + /** + * Updates a column specified by a column index with an Object value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @param scale + * for the types java.sql.Types.DECIMAL or + * java.sql.Types.NUMERIC, this specifies the number of digits + * after the decimal point. + * @throws SQLException + * if a database error happens + */ + public void updateObject(int columnIndex, Object x, int scale) + throws SQLException; + + /** + * Updates a column specified by a column name with an Object value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateObject(String columnName, Object x) throws SQLException; + + /** + * Updates a column specified by a column name with an Object value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @param scale + * for the types java.sql.Types.DECIMAL or + * java.sql.Types.NUMERIC, this specifies the number of digits + * after the decimal point. + * @throws SQLException + * if a database error happens + */ + public void updateObject(String columnName, Object x, int scale) + throws SQLException; + + /** + * Updates a column specified by a column index with a java.sql.Ref value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateRef(int columnIndex, Ref x) throws SQLException; + + /** + * Updates a column specified by a column name with a java.sql.Ref value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateRef(String columnName, Ref x) throws SQLException; + + /** + * Updates the database with the new contents of the current row of this + * ResultSet object. + * + * @throws SQLException + */ + public void updateRow() throws SQLException; + + /** + * Updates a column specified by a column index with a short value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateShort(int columnIndex, short x) throws SQLException; + + /** + * Updates a column specified by a column name with a short value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateShort(String columnName, short x) throws SQLException; + + /** + * Updates a column specified by a column index with a String value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateString(int columnIndex, String x) throws SQLException; + + /** + * Updates a column specified by a column name with a String value. + * + * @param columnName + * the name of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateString(String columnName, String x) throws SQLException; + + /** + * Updates a column specified by a column index with a Time value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateTime(int columnIndex, Time x) throws SQLException; + + /** + * Updates a column specified by a column name with a Time value. + * + * @param columnName + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateTime(String columnName, Time x) throws SQLException; + + /** + * Updates a column specified by a column index with a Timestamp value. + * + * @param columnIndex + * the index of the column to update + * @param x + * the new value for the specified column + * @throws SQLException + * if a database error happens + */ + public void updateTimestamp(int columnIndex, Timestamp x) + throws SQLException; + + /** + * Updates a column specified by column name with a Timestamp value. + * + * @param columnName + * the name of the column to update + * @param x + * @throws SQLException + * if a database error happens + */ + public void updateTimestamp(String columnName, Timestamp x) + throws SQLException; + + /** + * Determines if the last column read from this ResultSet contained SQL + * NULL. + * + * @return true if the last column contained SQL NULL, false otherwise + * @throws SQLException + * if a database error happens + */ + public boolean wasNull() throws SQLException; +} diff --git a/sql/src/main/java/java/sql/ResultSetMetaData.java b/sql/src/main/java/java/sql/ResultSetMetaData.java new file mode 100644 index 0000000..d530d11 --- /dev/null +++ b/sql/src/main/java/java/sql/ResultSetMetaData.java @@ -0,0 +1,277 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * Provides information about the columns in a ResultSet. + */ +public interface ResultSetMetaData { + + /** + * Indicates that a column cannot contain NULL values + */ + public static final int columnNoNulls = 0; + + /** + * Indicates that a column can contain NULL values + */ + public static final int columnNullable = 1; + + /** + * Indicates that it is unknown whether a column can contain NULLs or not + */ + public static final int columnNullableUnknown = 2; + + /** + * Returns the title of indexed columns catalog + * + * @param column + * the column index, starting at 1 + * @return the catalog title + * @throws SQLException + * if there is a database error + */ + public String getCatalogName(int column) throws SQLException; + + /** + * Returns the fully-qualified type of the class that is produced when + * invoking ResultSet.getObject to recover this columns value. + * + * @param column + * the column index, starting at 1 + * @return the fully-qualified class name + * @throws SQLException + * if there is a database error + */ + public String getColumnClassName(int column) throws SQLException; + + /** + * Returns a count of the columns in this set of results. + * + * @return the column count + * @throws SQLException + * if there is a database error + */ + public int getColumnCount() throws SQLException; + + /** + * Returns the indexed column's standard maximum width, expressed in number + * of characters. + * + * @param column + * the column index, starting at 1 + * @return the column's max width + * @throws SQLException + * if there is a database error + */ + public int getColumnDisplaySize(int column) throws SQLException; + + /** + * Returns a recommended title for the indexed column, to be used when the + * title needs to be displayed. + * + * @param column + * the column index, starting at 1 + * @return the column's title + * @throws SQLException + * if there is a database error + */ + public String getColumnLabel(int column) throws SQLException; + + /** + * Returns the title of the indexed column + * + * @param column + * the column index, starting at 1 + * @return the column title + * @throws SQLException + * if there is a database error + */ + public String getColumnName(int column) throws SQLException; + + /** + * Returns the type of the indexed column + * + * @param column + * the column index, starting at 1 + * @return the column type + * @throws SQLException + * if there is a database error + */ + public int getColumnType(int column) throws SQLException; + + /** + * Returns the type name of the indexed column + * + * @param column + * the column index, starting at 1 + * @return the type name + * @throws SQLException + * if there is a database error + */ + public String getColumnTypeName(int column) throws SQLException; + + /** + * Returns the decimal precision of the indexed column + * + * @param column + * the column index, starting at 1 + * @return the precision + * @throws SQLException + * if there is a database error + */ + public int getPrecision(int column) throws SQLException; + + /** + * Returns the number of decimal places in the indexed column. + * + * @param column + * the column index, starting at 1 + * @return number of decimal places + * @throws SQLException + * if there is a database error + */ + public int getScale(int column) throws SQLException; + + /** + * Returns the name of the indexed columns schema + * + * @param column + * the column index, starting at 1 + * @return the name of the columns schema + * @throws SQLException + * if there is a database error + */ + public String getSchemaName(int column) throws SQLException; + + /** + * Returns the title of the indexed columns table. + * + * @param column + * the column index, starting at 1 + * @return the table title + * @throws SQLException + * if there is a database error + */ + public String getTableName(int column) throws SQLException; + + /** + * Returns and indication of whether the indexed column has automatic + * numbering and is therefore read-only + * + * @param column + * the column index, starting at 1 + * @return true if it is automatically numbered, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isAutoIncrement(int column) throws SQLException; + + /** + * Returns an indicator of whether the case of the indexed column is + * important + * + * @param column + * the column index, starting at 1 + * @return true if case matters, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isCaseSensitive(int column) throws SQLException; + + /** + * Returns if the indexed column contains a monetary amount. + * + * @param column + * the column index, starting at 1 + * @return true if it is a monetary value, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isCurrency(int column) throws SQLException; + + /** + * Returns an indication of whether writing to the indexed column is + * guaranteed to be successful + * + * @param column + * the column index, starting at 1 + * @return true if the write is guaranteed, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isDefinitelyWritable(int column) throws SQLException; + + /** + * Returns whether the indexed column is nullable. + * + * @param column + * the column index, starting at 1 + * @return true if it is nullable, false otherwise + * @throws SQLException + * if there is a database error + */ + public int isNullable(int column) throws SQLException; + + /** + * Returns an indication of whether writing to the indexed column is + * guaranteed to be unsuccessful + * + * @param column + * the column index, starting at 1 + * @return true if the column is read-only, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isReadOnly(int column) throws SQLException; + + /** + * Returns an indication of whether the indexed column is searchable. + * + * @param column + * the column index, starting at 1 + * @return true if the indexed column is searchable, false otherwise. + * @throws SQLException + * if there is a database error + */ + public boolean isSearchable(int column) throws SQLException; + + /** + * Returns an indicator of whether the values contained in the indexed + * column are signed. + * + * @param column + * the column index, starting at 1 + * @return true if they are signed, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isSigned(int column) throws SQLException; + + /** + * Returns an indication of whether writing to the indexed column is + * possible. + * + * @param column + * the column index, starting at 1 + * @return true if it is possible to write, false otherwise + * @throws SQLException + * if there is a database error + */ + public boolean isWritable(int column) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/SQLData.java b/sql/src/main/java/java/sql/SQLData.java new file mode 100644 index 0000000..7b07835 --- /dev/null +++ b/sql/src/main/java/java/sql/SQLData.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * An interface for the custom mapping of an SQL User Defined Type (UDT) to a + * Java Class. The Java Class object will be added to the Connection's type map + * with the SQL Name of the UDT which it maps. + * <p> + * Usually within an implementation of SQLData, there is a corresponding field + * for every attribute of an SQL type, or only one field if the type is SQL + * DISTINCT. When the UDT is returned within a ResultSet, it is accessed with + * the ResultSet.getObject method and is returned as an Object which is an + * instance of the class defined by the SQLData mapping. The application can use + * this object just like any other Java object and can store changes back into + * the database using the PreparedStatement.setObject method which performs the + * reverse mapping into the SQL UDT. + * <p> + * It is standard for an implementation for a custom mapping to be generated by + * a tool. The tool usually requires the name of the SQL UDT, the name of the + * class which it is going to be mapped to, and the field names to which the UDT + * attributes will be mapped. The tool can then implement the SQLData readSQL + * and writeSQL methods. readSQL reads attributes from an SQLInput object, and + * writeSQL writes them. This is done via SQLInput and SQLOutput method calls + * respectively + * <p> + * Ordinarily a programmer would not call SQLData methods directly. Similarly + * SQLInput and SQLOutput methods are not usually called directly. + */ +public interface SQLData { + + /** + * Gets the SQL name of the User Defined Type (UDT) that this object + * represents. This method, usually invoked by the JDBC driver, retrieves + * the name of the UDT instance associated with this SQLData object. + * + * @return a string with UDT type name for this object mapping, passed to + * readSQL when the object was created + * @throws SQLException + * if a database error occurs + */ + public String getSQLTypeName() throws SQLException; + + /** + * Reads data from the database into this object. This method follows these + * steps: + * <ul> + * <li>Utilize the passed input stream to read the attributes or entries of + * the SQL type</li> + * <li>This is carried out by reading each entry from the input stream, + * ordered as the are the SQL definition.</li> + * <li>Assign the data to the appropriate fields or elements. This is done + * by calling the relevant reader method for the type involved (eg. + * SQLInput.readString, SQLInputreadBigDecimal). If the type is distinct, + * then read its only data entry. For structured types, read every entry.</li> + * </ul> + * The supplied input stream is typically initialized by the calling JDBC + * driver with the type map before readSQL is called. + * + * @param stream + * the SQLInput stream from which the type map data is read for + * the custom mapping + * @param typeName + * the SQL Type name for the type which is being mapped + * @throws SQLException + * if a database error occurs + */ + public void readSQL(SQLInput stream, String typeName) throws SQLException; + + /** + * Writes the object to a supplied SQLOutput data stream, writing it out as + * an SQL value to the data source. + * <p> + * This method follows the following steps: + * <ul> + * <li>Write each attribute of the SQL type to the output stream.</li> + * <li>Write each item by calling a method on the output stream, in the + * order they appear in the SQL definition of the type. Use the appropriate + * SQLOutput methods (eg. writeInt, writeString). Write a single data + * element for a Distinct type. For a Structured type, write a value for + * each attribute of the the SQL type.</li> + * </ul> + * + * @param stream + * the SQLOutput stream to use to write out the data for the + * custom mapping + * @throws SQLException + * if a database error occurs + */ + public void writeSQL(SQLOutput stream) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/SQLException.java b/sql/src/main/java/java/sql/SQLException.java new file mode 100644 index 0000000..07a4763 --- /dev/null +++ b/sql/src/main/java/java/sql/SQLException.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.Serializable; + +/** + * An Exception class that is used in conjunction with JDBC operations. It + * provides information about problems encountered with Database access and + * other problems related to JDBC + * <p> + * The SQLException class provides the following information: + * <ul> + * <li>A standard Java exception message, as a String + * <li>An SQLState string. This is an error description string which follows + * either the SQL 99 conventions or the XOPEN SQLstate conventions. The + * potential values of the SQLState string are described in each of the + * specifications. Which of the conventions is being used by the SQLState string + * can be discovered by using the getSQLStateType method of the DatabaseMetaData + * interface. + * <li>An Error Code, an an integer. The error code is specific to each + * database vendor and is typically the error code returned by the database + * itself. + * <li>A chain to a next Exception, if relevant, which can give access to + * additional error information. + * </ul> + */ +public class SQLException extends Exception implements Serializable { + + private static final long serialVersionUID = 2135244094396331484L; + + private String SQLState = null; + + private int vendorCode = 0; + + private SQLException next = null; + + /** + * Creates an SQLException object. The Reason string is set to null, the + * SQLState string is set to null and the Error Code is set to 0. + */ + public SQLException() { + super(); + } + + /** + * Creates an SQLException object. The Reason string is set to the given + * reason string, the SQLState string is set to null and the Error Code is + * set to 0. + * + * @param theReason + * the string to use as the Reason string + */ + public SQLException(String theReason) { + this(theReason, null, 0); + } + + /** + * Creates an SQLException object. The Reason string is set to the given + * reason string, the SQLState string is set to the given SQLState string + * and the Error Code is set to 0. + * + * @param theReason + * the string to use as the Reason string + * @param theSQLState + * the string to use as the SQLState string + */ + public SQLException(String theReason, String theSQLState) { + this(theReason, theSQLState, 0); + } + + /** + * Creates an SQLException object. The Reason string is set to the given + * reason string, the SQLState string is set to the given SQLState string + * and the Error Code is set to the given error code value. + * + * @param theReason + * the string to use as the Reason string + * @param theSQLState + * the string to use as the SQLState string + * @param theErrorCode + * the integer value for the error code + */ + public SQLException(String theReason, String theSQLState, int theErrorCode) { + super(theReason); + SQLState = theSQLState; + vendorCode = theErrorCode; + } + + /** + * Returns the integer error code for this SQLException + * + * @return The integer error code for this SQLException. The meaning of the + * code is specific to the vendor of the database. + */ + public int getErrorCode() { + return vendorCode; + } + + /** + * Retrieves the SQLException chained to this SQLException, if any. + * + * @return The SQLException chained to this SQLException. null if there is + * no SQLException chained to this SQLException. + */ + public SQLException getNextException() { + return next; + } + + /** + * Retrieves the SQLState description string for this SQLException object + * + * @return The SQLState string for this SQLException object. This is an + * error description string which follows either the SQL 99 + * conventions or the XOPEN SQLstate conventions. The potential + * values of the SQLState string are described in each of the + * specifications. Which of the conventions is being used by the + * SQLState string can be discovered by using the getSQLStateType + * method of the DatabaseMetaData interface. + */ + public String getSQLState() { + return SQLState; + } + + /** + * Adds the SQLException to the end of this SQLException chain. + * + * @param ex + * the new SQLException to be added to the end of the chain + */ + public void setNextException(SQLException ex) { + if (next != null) { + next.setNextException(ex); + } else { + next = ex; + } + } +} diff --git a/sql/src/main/java/java/sql/SQLInput.java b/sql/src/main/java/java/sql/SQLInput.java new file mode 100644 index 0000000..d30da9f --- /dev/null +++ b/sql/src/main/java/java/sql/SQLInput.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.math.BigDecimal; +import java.io.Reader; +import java.io.InputStream; +import java.net.URL; + +/** + * The SQLInput interface defines operations which apply to a type of input + * stream which carries a series of values which represent an instance of an SQL + * structured type or SQL distinct type. + * <p> + * SQLInput interface is used for custom mapping of SQL User Defined Types + * (UDTs)to Java classes. It is used by JDBC drivers below the level of the + * public interfaces and application programs do not normally use the SQLInput + * methods directly. Reader methods such as readLong and readBytes provide means + * to read values from an SQLInput stream. + * <p> + * When the getObject method is called with an object which implements the + * SQLData interface, the JDBC driver determines the SQL type of the UDT being + * mapped by calling the SQLData.getSQLType method. The driver creates an + * instance of an SQLInput stream, filling the stream with the attributes of the + * UDT. The SQLInput stream is passed to the SQLData.readSQL method which then + * calls the SQLInput reader methods to read the attributes. + */ +public interface SQLInput { + + /** + * Returns the next attribute in the stream in the form of a String. + * + * @return the next attribute as a String. null if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public String readString() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a boolean. + * + * @return the next attribute as a boolean. false if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public boolean readBoolean() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a byte. + * + * @return the next attribute as a byte. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public byte readByte() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a short. + * + * @return the next attribute as a short. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public short readShort() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of an int. + * + * @return the next attribute as an int. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public int readInt() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a long. + * + * @return the next attribute as a long. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public long readLong() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a float. + * + * @return the next attribute as a float. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public float readFloat() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a double. + * + * @return the next attribute as a double. 0 if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public double readDouble() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a + * java.math.BigDecimal. + * + * @return the attribute as a java.math.BigDecimal. null if the read returns + * SQL NULL. + * @throws SQLException + * if there is a database error + */ + public BigDecimal readBigDecimal() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a byte array. + * + * @return the attribute as a byte array. null if the read returns SQL NULL. + * @throws SQLException + * if there is a database error + */ + public byte[] readBytes() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Date. + * + * @return the next attribute as a java.sql.Date. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Date readDate() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Time. + * + * @return the attribute as a java.sql.Time. null if the read returns SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Time readTime() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a + * java.sql.Timestamp. + * + * @return the attribute as a java.sql.Timestamp. null if the read returns + * SQL NULL. + * @throws SQLException + * if there is a database error + */ + public Timestamp readTimestamp() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a Unicode + * character stream embodied as a java.io.Reader. + * + * @return the next attribute as a java.io.Reader. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Reader readCharacterStream() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of an ASCII + * character stream embodied as a java.io.InputStream. + * + * @return the next attribute as a java.io.InputStream. null if the value is + * SQL NULL. + * @throws SQLException + * if there is a database error + */ + public InputStream readAsciiStream() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a stream of bytes + * embodied as a java.io.InputStream. + * + * @return the next attribute as a java.io.InputStream. null if the value is + * SQL NULL. + * @throws SQLException + * if there is a database error + */ + public InputStream readBinaryStream() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a + * java.lang.Object. + * <p> + * The type of the Object returned is determined by the type mapping for + * this JDBC driver, including any customized mappings in force. A type map + * is given to the SQLInput by the JDBC driver before the SQLInput is given + * to the application. + * <p> + * If the attribute is an SQL structured or distinct type, its SQL type is + * determined. If the streams type map contains an element for that SQL + * type, the driver creates an object of relevant type and invokes the + * method SQLData.readSQL on it, which reads supplementary data from the + * stream using whichever protocol is defined for that method. + * + * @return the next attribute as an Object. null if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public Object readObject() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Ref. + * + * @return the next attribute as a java.sql.Ref. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Ref readRef() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Blob. + * + * @return the next attribute as a java.sql.Blob. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Blob readBlob() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Clob. + * + * @return the next attribute as a java.sql.Clob. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public Clob readClob() throws SQLException; + + /** + * Returns the next attribute in the stream in the form of a java.sql.Array. + * + * @return the next attribute as an Array. null if the value is SQL NULL. + * @throws SQLException + * if there is a database error + */ + public Array readArray() throws SQLException; + + /** + * Reports whether the last value read was SQL NULL. + * + * @return true if the last value read was SQL NULL, false otherwise. + * @throws SQLException + * if there is a database error + */ + public boolean wasNull() throws SQLException; + + /** + * Reads the next attribute in the stream (SQL DATALINK value) and returns + * it as a java.net.URL object. + * + * @return the next attribute as a java.net.URL. null if the value is SQL + * NULL. + * @throws SQLException + * if there is a database error + */ + public URL readURL() throws SQLException; +} diff --git a/sql/src/main/java/java/sql/SQLOutput.java b/sql/src/main/java/java/sql/SQLOutput.java new file mode 100644 index 0000000..287a5f6 --- /dev/null +++ b/sql/src/main/java/java/sql/SQLOutput.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.net.URL; + +/** + * The interface for an output stream used to write attributes of an SQL User + * Defined Type to the database. This interface is used for custom mapping of + * types and is called by the JDBC driver. It is not expected that this + * interface is used by applications. + * <p> + * When an object which implements the SQLData interface is used as an argument + * to an SQL statement, the JDBC driver calls the method + * <code>SQLData.getSQLType</code> to establish the type of the SQL UDT that + * is being passed. The driver then creates an SQLOutput stream and passes it to + * the <code>SQLData.writeSQL</code> method, which in turn uses the + * appropriate SQLOutput writer methods to write the data from the SQLData + * object into the stream according to the defined mapping. + */ +public interface SQLOutput { + + /** + * Write a String value into the output stream. + * + * @param theString + * the String to write + * @throws SQLException + * if a database error occurs + */ + public void writeString(String theString) throws SQLException; + + /** + * Write a boolean value into the output stream. + * + * @param theFlag + * the boolean value to write + * @throws SQLException + * if a database error occurs + */ + public void writeBoolean(boolean theFlag) throws SQLException; + + /** + * Write a byte value into the output stream. + * + * @param theByte + * the byte value to write + * @throws SQLException + * if a database error occurs + */ + public void writeByte(byte theByte) throws SQLException; + + /** + * Write a short value into the output stream. + * + * @param theShort + * the short value to write + * @throws SQLException + * if a database error occurs + */ + public void writeShort(short theShort) throws SQLException; + + /** + * Write an int value into the output stream. + * + * @param theInt + * the int value to write + * @throws SQLException + * if a database error occurs + */ + public void writeInt(int theInt) throws SQLException; + + /** + * Write a long value into the output stream. + * + * @param theLong + * the long value to write + * @throws SQLException + * if a database error occurs + */ + public void writeLong(long theLong) throws SQLException; + + /** + * Write a float value into the output stream. + * + * @param theFloat + * the float value to write + * @throws SQLException + * if a database error occurs + */ + public void writeFloat(float theFloat) throws SQLException; + + /** + * Write a double value into the output stream. + * + * @param theDouble + * the double value to write + * @throws SQLException + * if a database error occurs + */ + public void writeDouble(double theDouble) throws SQLException; + + /** + * Write a java.math.BigDecimal value into the output stream. + * + * @param theBigDecimal + * the BigDecimal value to write + * @throws SQLException + * if a database error occurs + */ + public void writeBigDecimal(BigDecimal theBigDecimal) throws SQLException; + + /** + * Write an array of bytes into the output stream. + * + * @param theBytes + * the array of bytes to write + * @throws SQLException + * if a database error occurs + */ + public void writeBytes(byte[] theBytes) throws SQLException; + + /** + * Write a java.sql.Date value into the output stream. + * + * @param theDate + * the Date value to write + * @throws SQLException + * if a database error occurs + */ + public void writeDate(Date theDate) throws SQLException; + + /** + * Write a java.sql.Time value into the output stream. + * + * @param theTime + * the Time value to write + * @throws SQLException + * if a database error occurs + */ + public void writeTime(Time theTime) throws SQLException; + + /** + * Write a java.sql.Timestamp value into the output stream. + * + * @param theTimestamp + * the Timestamp value to write + * @throws SQLException + * if a database error occurs + */ + public void writeTimestamp(Timestamp theTimestamp) throws SQLException; + + /** + * Write a stream of Unicode characters into the output stream. + * + * @param theStream + * the stream of Unicode characters to write, as a java.io.Reader + * object + * @throws SQLException + * if a database error occurs + */ + public void writeCharacterStream(Reader theStream) throws SQLException; + + /** + * Write a stream of ASCII characters into the output stream. + * + * @param theStream + * the stream of ASCII characters to write, as a + * java.io.InputStream object + * @throws SQLException + * if a database error occurs + */ + public void writeAsciiStream(InputStream theStream) throws SQLException; + + /** + * Write a stream of uninterpreted bytes into the output stream. + * + * @param theStream + * the stream of bytes to write, as a java.io.InputStream object + * @throws SQLException + * if a database error occurs + */ + public void writeBinaryStream(InputStream theStream) throws SQLException; + + /** + * Write an SQLData object into the output stream. + * <p> + * If the SQLData object is null, writes SQL NULL to the stream. + * <p> + * Otherwise, calls the <code>SQLData.writeSQL</code> method of the + * object, which writes the object's attributes to the stream by calling the + * appropriate SQLOutput writer methods for each attribute, in order. The + * order of the attributes is the order they are listed in the SQL + * definition of the User Defined Type. + * + * @param theObject + * the SQLData object to write + * @throws SQLException + * if a database error occurs + */ + public void writeObject(SQLData theObject) throws SQLException; + + /** + * Write an SQL Ref value into the output stream. + * + * @param theRef + * the java.sql.Ref object to write + * @throws SQLException + * if a database error occurs + */ + public void writeRef(Ref theRef) throws SQLException; + + /** + * Write an SQL Blob value into the output stream. + * + * @param theBlob + * the java.sql.Blob object to write + * @throws SQLException + * if a database error occurs + */ + public void writeBlob(Blob theBlob) throws SQLException; + + /** + * Write an SQL Clob value into the output stream. + * + * @param theClob + * the java.sql.Clob object to write + * @throws SQLException + * if a database error occurs + */ + public void writeClob(Clob theClob) throws SQLException; + + /** + * Write an SQL Struct value into the output stream. + * + * @param theStruct + * the java.sql.Struct object to write + * @throws SQLException + * if a database error occurs + */ + public void writeStruct(Struct theStruct) throws SQLException; + + /** + * Write an SQL Array value into the output stream. + * + * @param theArray + * the java.sql.Array object to write + * @throws SQLException + * if a database error occurs + */ + public void writeArray(Array theArray) throws SQLException; + + /** + * Write an SQL DATALINK value into the output stream. + * + * @param theURL + * the Datalink value as a java.net.URL to write + * @throws SQLException + * if a database error occurs + */ + public void writeURL(URL theURL) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/SQLPermission.java b/sql/src/main/java/java/sql/SQLPermission.java new file mode 100644 index 0000000..734f1f2 --- /dev/null +++ b/sql/src/main/java/java/sql/SQLPermission.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.Serializable; +import java.security.BasicPermission; +import java.security.Guard; + +/** + * Permission relating to security access control in the java.sql package. + * <p> + * Currently, the only permission supported has the name "setLog". The setLog + * permission controls whether a Java application or applet can open a logging + * stream using the DriverManager.setLogWriter method or the + * DriverManager.setLogStream method. This is a potentially dangerous operation + * since the logging stream can contain usernames, passwords + */ +public final class SQLPermission extends BasicPermission implements Guard, + Serializable { + + private static final long serialVersionUID = -1439323187199563495L; + + /** + * Creates a new SQLPermission object with the specified name. + * + * @param name + * the name to use for this SQLPermission + */ + public SQLPermission(String name) { + super(name); + } + + /** + * Creates a new SQLPermission object with the specified name. + * + * @param name + * is the name of the SQLPermission. Currently only "setLog" is + * allowed. + * @param actions + * is currently unused and should be set to null + */ + public SQLPermission(String name, String actions) { + super(name, null); + } +} diff --git a/sql/src/main/java/java/sql/SQLWarning.java b/sql/src/main/java/java/sql/SQLWarning.java new file mode 100644 index 0000000..efaf216 --- /dev/null +++ b/sql/src/main/java/java/sql/SQLWarning.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.io.Serializable; + +import org.apache.harmony.sql.internal.nls.Messages; + +/** + * An exception class that holds information about Database access warnings. + */ +public class SQLWarning extends SQLException implements Serializable { + + private static final long serialVersionUID = 3917336774604784856L; + + /** + * Creates an SQLWarning object. The Reason string is set to null, the + * SQLState string is set to null and the Error Code is set to 0. + */ + public SQLWarning() { + super(); + } + + /** + * Creates an SQLWarning object. The Reason string is set to the given + * reason string, the SQLState string is set to null and the Error Code is + * set to 0. + * + * @param theReason + */ + public SQLWarning(String theReason) { + super(theReason); + } + + /** + * Creates an SQLWarning object. The Reason string is set to the given + * reason string, the SQLState string is set to the given SQLState string + * and the Error Code is set to 0. + * + * @param theReason + * the string to use as the Reason string + * @param theSQLState + * the string to use as the SQLState string + */ + public SQLWarning(String theReason, String theSQLState) { + super(theReason, theSQLState); + } + + /** + * Creates an SQLWarning object. The Reason string is set to the given + * reason string, the SQLState string is set to the given SQLState string + * and the Error Code is set to the given ErrorCode value. + * + * @param theReason + * @param theSQLState + * @param theErrorCode + */ + public SQLWarning(String theReason, String theSQLState, int theErrorCode) { + super(theReason, theSQLState, theErrorCode); + } + + /** + * Gets the SQLWarning chained to this SQLWarning object. + * + * @return the SQLWarning chained to this SQLWarning. null if no SQLWarning + * is chained to this SQLWarning. + */ + public SQLWarning getNextWarning() { + SQLException next = super.getNextException(); + if (next == null) { + return null; + } + if (next instanceof SQLWarning) { + return (SQLWarning) next; + } + throw new Error(Messages.getString("sql.8")); //$NON-NLS-1$ + } + + /** + * Chains a supplied SQLWarning to this SQLWarning. + * + * @param w + * the SQLWarning to chain to this SQLWarning. + */ + public void setNextWarning(SQLWarning w) { + super.setNextException(w); + } +} diff --git a/sql/src/main/java/java/sql/Savepoint.java b/sql/src/main/java/java/sql/Savepoint.java new file mode 100644 index 0000000..fd27877 --- /dev/null +++ b/sql/src/main/java/java/sql/Savepoint.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * A Savepoint is an instant during the current transaction that can be utilized + * by a Rollback from the Connection.rollback method. Rolling back to a + * particular Savepoint means that all changes that occurred after that + * Savepoint are removed. + */ +public interface Savepoint { + + /** + * Returns the constructed ID for this Savepoint. + * + * @return the ID for this Savepoint. + * @throws SQLException + */ + public int getSavepointId() throws SQLException; + + /** + * Returns the name for this Savepoint. + * + * @return the name of this Savepoint. + * @throws SQLException + */ + public String getSavepointName() throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Statement.java b/sql/src/main/java/java/sql/Statement.java new file mode 100644 index 0000000..8896dbf --- /dev/null +++ b/sql/src/main/java/java/sql/Statement.java @@ -0,0 +1,620 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * Interface used for executing static SQL statements and returning their + * results. + * + * By default, an object implementing the Statement interface can returns + * results as ResultSets. For any given Statement object, only one ResultSet can + * be open at one time. A call to any of the execution methods of Statement will + * cause any previously created ResultSet object for that Statement to be closed + * implicitly. + * <p> + * To have multiple ResultSet objects open concurrently, multiple Statement + * objects must be used. + */ +public interface Statement { + + /** + * Passing this constant to getMoreResults implies that all ResultSet + * objects previously kept open should be closed. + */ + public static final int CLOSE_ALL_RESULTS = 3; + + /** + * Passing this constant to getMoreResults implies that the current + * ResultSet object should be closed + */ + public static final int CLOSE_CURRENT_RESULT = 1; + + /** + * Indicates that an error was encountered during execution of a batch + * statement. + */ + public static final int EXECUTE_FAILED = -3; + + /** + * Passing this constant to getMoreResults implies that the current + * ResultSet object should not be closed. + */ + public static final int KEEP_CURRENT_RESULT = 2; + + /** + * Indicates that generated keys should not be accessible for retrieval. + */ + public static final int NO_GENERATED_KEYS = 2; + + /** + * Indicates that generated keys should be accessible for retrieval. + */ + public static final int RETURN_GENERATED_KEYS = 1; + + /** + * Indicates that a batch statement was executed with a successful result, + * but a count of the number of rows it affected is unavailable. + */ + public static final int SUCCESS_NO_INFO = -2; + + /** + * Adds a specified SQL commands to the list of commands for this Statement. + * <p> + * The list of commands is executed by invoking the + * <code>executeBatch</code> method. + * + * @param sql + * the SQL command as a String. Typically an INSERT or UPDATE + * statement. + * @throws SQLException + * if an error occurs accessing the database or the database + * does not support batch updates + */ + public void addBatch(String sql) throws SQLException; + + /** + * Cancels this Statement execution if both the database and the JDBC driver + * support aborting an SQL statement in flight. This method can be used by + * one thread to stop a Statement that is being executed on another thread. + * + * @throws SQLException + * if an error occurs accessing the database + */ + public void cancel() throws SQLException; + + /** + * Clears the current list of SQL commands for this Statement. + * + * @throws SQLException + * if an error occurs accessing the database or the database + * does not support batch updates + */ + public void clearBatch() throws SQLException; + + /** + * Clears all SQLWarnings from this Statement. + * + * @throws SQLException + * if an error occurs accessing the database + */ + public void clearWarnings() throws SQLException; + + /** + * Releases this Statement's database and JDBC driver resources. + * <p> + * Using this method to release these resources as soon as possible is + * strongly recommended. It is not a good idea to rely on these resources + * being released when the Statement object is finalized during garbage + * collection. Doing so can result in unpredictable performance + * characteristics for the application. + * + * @throws SQLException + * if an error occurs accessing the database + */ + public void close() throws SQLException; + + /** + * Executes a supplied SQL statement. This may return multiple ResultSets. + * <p> + * Use the <code>getResultSet</code> or <code>getUpdateCount</code> + * methods to get the first result and <code>getMoreResults</code> to get + * any subsequent results. + * + * @param sql + * the SQL statement to execute + * @return true if the first result is a ResultSet, false if the first + * result is an update count or if there is no result + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean execute(String sql) throws SQLException; + + /** + * Executes a supplied SQL statement. This may return multiple ResultSets. + * This method allows control of whether auto-generated Keys should be made + * available for retrieval, if the SQL statement is an INSERT statement. + * <p> + * Use the <code>getResultSet</code> or <code>getUpdateCount</code> + * methods to get the first result and <code>getMoreResults</code> to get + * any subsequent results. + * + * @param sql + * the SQL statement to execute + * @param autoGeneratedKeys + * a flag indicating whether to make auto generated keys + * available for retrieval. This parameter must be one of + * Statement.NO_GENERATED_KEYS or Statement.RETURN_GENERATED_KEYS + * @return true if results exists and the first result is a ResultSet, false + * if the first result is an update count or if there is no result + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean execute(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * Executes the supplied SQL statement. This may return multiple ResultSets. + * This method allows retrieval of auto generated keys specified by the + * supplied array of column indexes, if the SQL statement is an INSERT + * statement. + * <p> + * Use the <code>getResultSet</code> or <code>getUpdateCount</code> + * methods to get the first result and <code>getMoreResults</code> to get + * any subsequent results. + * + * @param sql + * the SQL statement to execute + * @param columnIndexes + * an array of indexes of the columns in the inserted row which + * should be made available for retrieval via the + * <code>getGeneratedKeys</code> method. + * @return true if the first result is a ResultSet, false if the first + * result is an update count or if there is no result + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean execute(String sql, int[] columnIndexes) throws SQLException; + + /** + * Executes the supplied SQL statement. This may return multiple ResultSets. + * This method allows retrieval of auto generated keys specified by the + * supplied array of column indexes, if the SQL statement is an INSERT + * statement. + * <p> + * Use the <code>getResultSet</code> or <code>getUpdateCount</code> + * methods to get the first result and <code>getMoreResults</code> to get + * any subsequent results. + * + * @param sql + * the SQL statement to execute + * @param columnNames + * an array of column names in the inserted row which should be + * made available for retrieval via the + * <code>getGeneratedKeys</code> method. + * @return true if the first result is a ResultSet, false if the first + * result is an update count or if there is no result + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean execute(String sql, String[] columnNames) + throws SQLException; + + /** + * Submits a batch of SQL commands to the database. Returns an array of + * update counts, if all the commands execute successfully. + * <p> + * If one of the commands in the batch fails, this method can throw a + * BatchUpdateException and the JDBC driver may or may not process the + * remaining commands. The JDBC driver must behave consistently with the + * underlying database, either always continuing or never continuing. If the + * driver continues processing, the array of results returned contains the + * same number of elements as there are commands in the batch, with a + * minimum of one of the elements having the EXECUTE_FAILED value. + * + * @return an array of update counts, with one entry for each command in the + * batch. The elements are ordered according to the order in which + * the commands were added to the batch. + * <p> + * <ol> + * <li> If the value of an element is >=0, the corresponding command + * completed successfully and the value is the update count for that + * command, which is the number of rows in the database affected by + * the command.</li> + * <li> If the value is SUCCESS_NO_INFO, the command completed + * successfully but the number of rows affected is unknown. + * <li> + * <li> If the value is EXECUTE_FAILED, the command failed. + * </ol> + * @throws SQLException + * if an error occurs accessing the database + */ + public int[] executeBatch() throws SQLException; + + /** + * Executes a supplied SQL statement. Returns a single ResultSet. + * + * @param sql + * an SQL statement to execute. Typically a SELECT statement + * @return a ResultSet containing the data produced by the SQL statement. + * Never null. + * @throws SQLException + * if an error occurs accessing the database or if the statement + * produces anything other than a single ResultSet + */ + public ResultSet executeQuery(String sql) throws SQLException; + + /** + * Executes the supplied SQL statement. The statement may be an INSERT, + * UPDATE or DELETE statement or a statement which returns nothing. + * + * @param sql + * an SQL statement to execute - an SQL INSERT, UPDATE, DELETE or + * a statement which returns nothing + * @return the count of updated rows, or 0 for a statement that returns + * nothing. + * @throws SQLException + * if an error occurs accessing the database or if the statement + * produces a ResultSet + */ + public int executeUpdate(String sql) throws SQLException; + + /** + * Executes the supplied SQL statement. This method allows control of + * whether auto-generated Keys should be made available for retrieval. + * + * @param sql + * an SQL statement to execute - an SQL INSERT, UPDATE, DELETE or + * a statement which does not return anything. + * @param autoGeneratedKeys + * a flag that indicates whether to allow retrieval of auto + * generated keys. Parameter must be one of + * Statement.RETURN_GENERATED_KEYS or Statement.NO_GENERATED_KEYS + * @return the number of updated rows, or 0 if the statement returns + * nothing. + * @throws SQLException + * if an error occurs accessing the database or if the statement + * produces a ResultSet + */ + public int executeUpdate(String sql, int autoGeneratedKeys) + throws SQLException; + + /** + * Executes the supplied SQL statement. This method allows retrieval of auto + * generated keys specified by the supplied array of column indexes. + * + * @param sql + * an SQL statement to execute - an SQL INSERT, UPDATE, DELETE or + * a statement which returns nothing + * @param columnIndexes + * an array of indexes of the columns in the inserted row which + * should be made available for retrieval via the + * <code>getGeneratedKeys</code> method. + * @return the count of updated rows, or 0 for a statement that returns + * nothing. + * @throws SQLException + * if an error occurs accessing the database or if the statement + * produces a ResultSet + */ + public int executeUpdate(String sql, int[] columnIndexes) + throws SQLException; + + /** + * Executes the supplied SQL statement. This method allows retrieval of auto + * generated keys specified by the supplied array of column names. + * + * @param sql + * an SQL statement to execute - an SQL INSERT, UPDATE, DELETE or + * a statement which returns nothing + * @param columnNames + * an array of column names in the inserted row which should be + * made available for retrieval via the + * <code>getGeneratedKeys</code> method. + * @return the count of updated rows, or 0 for a statement that returns + * nothing. + * @throws SQLException + * if an error occurs accessing the database or if the statement + * produces a ResultSet + */ + public int executeUpdate(String sql, String[] columnNames) + throws SQLException; + + /** + * Gets the Connection that produced this Statement. + * + * @return the Connection + * @throws SQLException + * if an error occurs accessing the database + */ + public Connection getConnection() throws SQLException; + + /** + * Gets the default direction for fetching rows for ResultSets generated + * from this Statement. + * + * @return an integer describing the default fetch direction, one of: + * ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE, + * ResultSet.FETCH_UNKNOWN + * @throws SQLException + * if an error occurs accessing the database + */ + public int getFetchDirection() throws SQLException; + + /** + * Gets the default number of rows for a fetch for the ResultSet objects + * returned from this Statement. + * + * @return the default fetch size for ResultSets produced by this Statement + * @throws SQLException + * if an error occurs accessing the database + */ + public int getFetchSize() throws SQLException; + + /** + * Returns auto generated keys created by executing this Statement. + * + * @return a ResultSet containing the auto generated keys - empty if no keys + * were generated by the Statement + * @throws SQLException + * if an error occurs accessing the database + */ + public ResultSet getGeneratedKeys() throws SQLException; + + /** + * Gets the maximum number of bytes which can be returned for values from + * Character and Binary values in a ResultSet derived from this Statement. + * This limit applies to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, + * and LONGVARCHAR types. Any data exceeding the maximum size is abandoned + * without announcement. + * + * @return the current size limit, where 0 means that there is no limit + * @throws SQLException + * if an error occurs accessing the database + */ + public int getMaxFieldSize() throws SQLException; + + /** + * Gets the maximum number of rows that a ResultSet can contain when + * produced from this Statement. If the limit is exceeded, the excess rows + * are discarded silently. + * + * @return the current row limit, where 0 means that there is no limit. + * @throws SQLException + * if an error occurs accessing the database + */ + public int getMaxRows() throws SQLException; + + /** + * Moves to this Statement's next result. Returns true if it is a ResultSet. + * Any current ResultSet objects previously obtained with + * <code>getResultSet()</code> are closed implicitly. + * + * @return true if the next result is a ResultSet, false if the next result + * is not a ResultSet or if there are no more results. Note that if + * there is no more data, this method will return false and + * <code>getUpdateCount</code> will return -1. + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean getMoreResults() throws SQLException; + + /** + * Moves to this Statement's next result. Returns true if the next result is + * a ResultSet. Any current ResultSet objects previously obtained with + * <code>getResultSet()</code> are handled as indicated by a supplied Flag + * parameter. + * + * @param current + * a flag indicating what to do with existing ResultSets. This + * parameter must be one of Statement.CLOSE_ALL_RESULTS, + * Statement.CLOSE_CURRENT_RESULT or + * Statement.KEEP_CURRENT_RESULT. + * @return true if the next result exists and is a ResultSet, false if the + * next result is not a ResultSet or if there are no more results. + * Note that if there is no more data, this method will return false + * and <code>getUpdateCount</code> will return -1. + * @throws SQLException + * if an error occurs accessing the database + */ + public boolean getMoreResults(int current) throws SQLException; + + /** + * Gets the timeout value for Statement execution. The JDBC driver will wait + * up to this value for the execution to complete - after the limit is + * exceeded an SQL Exception is thrown. + * + * @return the current Query Timeout value, where 0 indicates that there is + * no current timeout. + * @throws SQLException + * if an error occurs accessing the database + */ + public int getQueryTimeout() throws SQLException; + + /** + * Gets the current result. Should only be called once per result. + * + * @return the ResultSet for the current result. null if the result is an + * update count or if there are no more results. + * @throws SQLException + * if an error occurs accessing the database + */ + public ResultSet getResultSet() throws SQLException; + + /** + * Gets the concurrency setting for ResultSet objects generated by this + * Statement. + * + * @return ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE + * @throws SQLException + * if an error occurs accessing the database + */ + public int getResultSetConcurrency() throws SQLException; + + /** + * Gets the cursor hold setting for ResultSet objects generated by this + * Statement. + * + * @return ResultSet.HOLD_CURSORS_OVER_COMMIT or + * ResultSet.CLOSE_CURSORS_AT_COMMIT + * @throws SQLException + * if there is an error while accessing the database + */ + public int getResultSetHoldability() throws SQLException; + + /** + * Gets the ResultSet type setting for ResultSets derived from this + * Statement. + * + * @return ResultSet.TYPE_FORWARD_ONLY for a ResultSet where the cursor can + * only move forward, ResultSet.TYPE_SCROLL_INSENSITIVE for a + * ResultSet which is Scrollable but is not sensitive to changes + * made by others, ResultSet.TYPE_SCROLL_SENSITIVE for a ResultSet + * which is Scrollable but is sensitive to changes made by others + * @throws SQLException + * if there is an error accessing the database + */ + public int getResultSetType() throws SQLException; + + /** + * Gets an update count for the current result if it is not a ResultSet. + * + * @return the current result as an update count. -1 if the current result + * is a ResultSet or if there are no more results + * @throws SQLException + * if an error occurs accessing the database + */ + public int getUpdateCount() throws SQLException; + + /** + * Retrieves the first SQLWarning reported by calls on this Statement. + * <p> + * If there are multiple warnings, subsequent warnings are chained to the + * first one. + * <p> + * The chain or warnings is cleared each time the Statement is executed. + * <p> + * Warnings associated with reads from the ResultSet returned from executing + * a Statement will be attached to the ResultSet, not the Statement object. + * + * @return an SQLWarning, null if there are no warnings + * @throws SQLException + * if an error occurs accessing the database + */ + public SQLWarning getWarnings() throws SQLException; + + /** + * Sets the SQL cursor name. This name is used by subsequent Statement + * execute methods. + * <p> + * Cursor names must be unique within one Connection. + * <p> + * With the Cursor name set, it can then be utilized in SQL positioned + * update or delete statements to determine the current row in a ResultSet + * generated from this Statement. The positioned update or delete must be + * done with a different Statement than this one. + * + * @param name + * the Cursor name as a String, + * @throws SQLException + * if an error occurs accessing the database + */ + public void setCursorName(String name) throws SQLException; + + /** + * Sets Escape Processing mode. + * <p> + * If Escape Processing is on, the JDBC driver will do escape substitution + * on an SQL statement before sending it for execution. This does not apply + * to PreparedStatements since they are processed when created, before this + * method can be called. + * + * @param enable + * true to set escape processing mode on, false to turn it off. + * @throws SQLException + * if an error occurs accessing the database + */ + public void setEscapeProcessing(boolean enable) throws SQLException; + + /** + * Sets the fetch direction - a hint to the JDBC driver about the direction + * of processing of rows in ResultSets created by this Statement. The + * default fetch direction is FETCH_FORWARD. + * + * @param direction + * which fetch direction to use. This parameter should be one of + * ResultSet.FETCH_UNKNOWN, ResultSet.FETCH_FORWARD or + * ResultSet.FETCH_REVERSE + * @throws SQLException + * if there is an error while accessing the database or if the + * fetch direction is unrecognized + */ + public void setFetchDirection(int direction) throws SQLException; + + /** + * Sets the fetch size. This is a hint to the JDBC driver about how many + * rows should be fetched from the database when more are required by + * application processing. + * + * @param rows + * the number of rows that should be fetched. 0 tells the driver + * to ignore the hint. Should be less than + * <code>getMaxRows</code> for this statement. Should not be + * negative. + * @throws SQLException + * if an error occurs accessing the database, or if the rows + * parameter is out of range. + */ + public void setFetchSize(int rows) throws SQLException; + + /** + * Sets the maximum number of bytes for ResultSet columns that contain + * character or binary values. This applies to BINARY, VARBINARY, + * LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR fields. Any data exceeding + * the maximum size is abandoned without announcement. + * + * @param max + * the maximum field size in bytes. O means "no limit". + * @throws SQLException + * if an error occurs accessing the database or the max value is + * <0. + */ + public void setMaxFieldSize(int max) throws SQLException; + + /** + * Sets the maximum number of rows that any ResultSet can contain. If the + * number of rows exceeds this value, the additional rows are silently + * discarded. + * + * @param max + * the maximum number of rows. 0 means "no limit". + * @throws SQLException + * if an error occurs accessing the database or if max <0. + */ + public void setMaxRows(int max) throws SQLException; + + /** + * Sets the timeout, in seconds, for queries - how long the driver will + * allow for completion of a Statement execution. If the timeout is + * exceeded, the query will throw an SQLException. + * + * @param seconds + * timeout in seconds. 0 means no timeout ("wait forever") + * @throws SQLException + * if an error occurs accessing the database or if seconds <0. + */ + public void setQueryTimeout(int seconds) throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Struct.java b/sql/src/main/java/java/sql/Struct.java new file mode 100644 index 0000000..0404cb7 --- /dev/null +++ b/sql/src/main/java/java/sql/Struct.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.util.Map; + +/** + * An interface which provides facilities for mapping an SQL structured type to + * Java. The Struct object has a value for each attribute of the SQL structured + * type + */ +public interface Struct { + + /** + * Gets the SQL Type name of the SQL structured type that this Struct + * represents + * + * @return the fully qualified name of SQL structured type + * @throws SQLException + * if a database error occurs + */ + public String getSQLTypeName() throws SQLException; + + /** + * Gets the values of the attributes of this SQL structured type. This + * method uses the type map associated with the Connection for customized + * type mappings. Where there is no entry in the Type Map which matches the + * this structured type, the JDBC driver uses the standard mapping. + * + * @return an Object array containing the attributes, in order + * @throws SQLException + * if a database error occurs + */ + public Object[] getAttributes() throws SQLException; + + /** + * Gets the values of the attributes of this SQL structured type. This + * method uses the supplied type map for customized type mappings. Where + * there is no entry in the Type Map which matches the this structured type, + * the JDBC driver uses the default mapping. The Connection type map is + * never utilized by this method. + * + * @param theMap + * a Map describing how SQL Type names are mapped to classes. + * @return an Object array containing the attributes, in order + * @throws SQLException + * if a database error occurs + */ + public Object[] getAttributes(Map<String, Class<?>> theMap) + throws SQLException; +} diff --git a/sql/src/main/java/java/sql/Time.java b/sql/src/main/java/java/sql/Time.java new file mode 100644 index 0000000..048259d --- /dev/null +++ b/sql/src/main/java/java/sql/Time.java @@ -0,0 +1,221 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Java representation of an SQL TIME value. Provides functions to aid + * generation and interpretation of JDBC escape format for time values. + * + */ +public class Time extends Date { + + private static final long serialVersionUID = 8397324403548013681L; + + /** + * @deprecated Please use the constructor {@link #Time(long)} Constructs a Time + * object using the supplied values for Hour, Minute and Second. + * The Year, Month and Day elements of the Time object are set + * to 1970, January, 1 reflecting the Epoch (Time in + * milliseconds = 0). + * <p> + * Any attempt to access the Year, Month or Day elements of a + * Time object will result in an IllegalArgumentException. + * <p> + * Result is undefined if any argument is out of bounds. + * @param theHour + * a value from 0 - 23 + * @param theMinute + * a value from 0 - 59 + * @param theSecond + * a value from 0 - 59 + */ + @SuppressWarnings("deprecation") + @Deprecated + public Time(int theHour, int theMinute, int theSecond) { + super(70, 0, 1, theHour, theMinute, theSecond); + } + + /** + * Constructs a Time object using a supplied time specified in milliseconds + * + * @param theTime + * a Time specified in milliseconds since the Epoch (January 1st + * 1970, 00:00:00.000) + */ + public Time(long theTime) { + super(theTime); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Date component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getDate() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Day component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getDay() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Month component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getMonth() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Year component. + * @return does not return + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getYear() { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Date component. + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setDate(int i) { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Month component. + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setMonth(int i) { + throw new IllegalArgumentException(); + } + + /** + * @deprecated This method is deprecated and must not be used. An SQL Time + * object does not have a Year component. + * @throws IllegalArgumentException + * if this method is called + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public void setYear(int i) { + throw new IllegalArgumentException(); + } + + /** + * Sets the time for this Time object to the supplied milliseconds value. + * + * @param time + * A time value expressed as milliseconds since the Epoch. + * Negative values are milliseconds before the Epoch. The Epoch + * is January 1 1970, 00:00:00.000 + */ + @Override + public void setTime(long time) { + super.setTime(time); + } + + /** + * Formats the Time as a String in JDBC escape format: hh:mm:ss + * + * @return A String representing the Time value in JDBC escape format: + * HH:mm:ss + */ + @Override + public String toString() { + SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); //$NON-NLS-1$ + return dateFormat.format(this); + } + + /** + * Creates a Time object from a String holding a time represented in JDBC + * escape format: hh:mm:ss. + * <p> + * An exception occurs if the input string is not in the form of a time in + * JDBC escape format. + * + * @param timeString + * A String representing the time value in JDBC escape format: + * hh:mm:ss + * @return The Time object set to a time corresponding to the given time + * @throws IllegalArgumentException + * if the supplied time string is not in JDBC escape format. + */ + public static Time valueOf(String timeString) { + if (timeString == null) { + throw new IllegalArgumentException(); + } + int firstIndex = timeString.indexOf(':'); + int secondIndex = timeString.indexOf(':', firstIndex + 1); + // secondIndex == -1 means none or only one separator '-' has been found. + // The string is separated into three parts by two separator characters, + // if the first or the third part is null string, we should throw + // IllegalArgumentException to follow RI + if (secondIndex == -1|| firstIndex == 0 || secondIndex + 1 == timeString.length()) { + throw new IllegalArgumentException(); + } + // parse each part of the string + int hour = Integer.parseInt(timeString.substring(0, firstIndex)); + int minute = Integer.parseInt(timeString.substring(firstIndex + 1, secondIndex)); + int second = Integer.parseInt(timeString.substring(secondIndex + 1, timeString + .length())); + return new Time(hour, minute, second); + } +} diff --git a/sql/src/main/java/java/sql/Timestamp.java b/sql/src/main/java/java/sql/Timestamp.java new file mode 100644 index 0000000..da8fa7a --- /dev/null +++ b/sql/src/main/java/java/sql/Timestamp.java @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +import java.text.DecimalFormat; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.harmony.sql.internal.nls.Messages; + +/** + * A Java representation of the SQL TIMESTAMP type. It provides the capability + * to represent the SQL TIMESTAMP nanosecond value, in addition to the regular + * date/time value which has millisecond resolution. + * <p> + * The Timestamp class consists of a regular Date/Time value, where only the + * integral seconds value is stored, plus a nanoseconds value where the + * fractional seconds are stored. + * <p> + * The addition of the nanosecond value field to the Timestamp object makes it + * significantly different from the java.util.Date object which it extends. + * Users should be cautious in their use of Timestamp objects and should not + * assume that they are interchangeable with java.util.Date objects when used + * outside the confines of the java.sql package. + * + */ +public class Timestamp extends Date { + + private static final long serialVersionUID = 2745179027874758501L; + + // The nanoseconds time value of the Timestamp + private int nanos; + + /** + * @deprecated Please use the constructor {@link #Timestamp(long)} Returns a + * Timestamp corresponding to the time specified by the supplied + * values for Year, Month, Date, Hour, Minutes, Seconds and + * Nanoseconds + * @param theYear + * specified as the year minus 1900 + * @param theMonth + * specified as an integer in the range 0 - 11 + * @param theDate + * specified as an integer in the range 1 - 31 + * @param theHour + * specified as an integer in the range 0 - 23 + * @param theMinute + * specified as an integer in the range 0 - 59 + * @param theSecond + * specified as an integer in the range 0 - 59 + * @param theNano + * which defines the nanosecond value of the timestamp specified + * as an integer in the range 0 - 999,999,999 + * @throws IllegalArgumentException + * if any of the parameters is out of range + */ + @SuppressWarnings("deprecation") + @Deprecated + public Timestamp(int theYear, int theMonth, int theDate, int theHour, + int theMinute, int theSecond, int theNano) + throws IllegalArgumentException { + super(theYear, theMonth, theDate, theHour, theMinute, theSecond); + if (theNano < 0 || theNano > 999999999) { + throw new IllegalArgumentException(); + } + nanos = theNano; + } + + /** + * Returns a Timestamp object corresponding to the time represented by a + * supplied time value. + * + * @param theTime + * a time value in the format of milliseconds since the Epoch + * (January 1 1970 00:00:00.000 GMT) + */ + public Timestamp(long theTime) { + super(theTime); + /* + * Now set the time for this Timestamp object - which deals with the + * nanosecond value as well as the base time + */ + this.setTime(theTime); + } + + /** + * Returns true if this timestamp object is later than the supplied + * timestamp, otherwise returns false. + * + * @param theTimestamp + * the timestamp to compare with this timestamp object + * @return true if this timestamp object is later than the supplied + * timestamp, false otherwise + */ + public boolean after(Timestamp theTimestamp) { + long thisTime = this.getTime(); + long compareTime = theTimestamp.getTime(); + + // If the time value is later, the timestamp is later + if (thisTime > compareTime) { + return true; + } + // If the time value is earlier, the timestamp is not later + else if (thisTime < compareTime) { + return false; + } + /* + * Otherwise the time values are equal in which case the nanoseconds + * value determines whether this timestamp is later... + */ + else if (this.getNanos() > theTimestamp.getNanos()) { + return true; + } else { + return false; + } + } + + /** + * Returns true if this timestamp object is earlier than the supplied + * timestamp, otherwise returns false. + * + * @param theTimestamp + * the timestamp to compare with this timestamp object + * @return true if this timestamp object is earlier than the supplied + * timestamp, false otherwise + */ + public boolean before(Timestamp theTimestamp) { + long thisTime = this.getTime(); + long compareTime = theTimestamp.getTime(); + + // If the time value is later, the timestamp is later + if (thisTime < compareTime) { + return true; + } + // If the time value is earlier, the timestamp is not later + else if (thisTime > compareTime) { + return false; + } + /* + * Otherwise the time values are equal in which case the nanoseconds + * value determines whether this timestamp is later... + */ + else if (this.getNanos() < theTimestamp.getNanos()) { + return true; + } else { + return false; + } + } + + /** + * Compares this Timestamp object with a supplied Timestamp object + * + * @param theObject + * the timestamp to compare with this timestamp object, passed in + * as an Object + * @return 0 if the two Timestamp objects are equal in time, a value <0 if + * this Timestamp object is before the supplied Timestamp and a + * value >0 if this Timestamp object is after the supplied Timestamp + * @throws ClassCastException + * if the supplied object is not a Timestamp object + */ + @Override + public int compareTo(Date theObject) throws ClassCastException { + return this.compareTo((Timestamp) theObject); + } + + /** + * Compares this Timestamp object with a supplied Timestamp object + * + * @param theTimestamp + * the timestamp to compare with this timestamp object, passed in + * as a Timestamp + * @return 0 if the two Timestamp objects are equal in time, a value <0 if + * this Timestamp object is before the supplied Timestamp and a + * value >0 if this Timestamp object is after the supplied Timestamp + */ + public int compareTo(Timestamp theTimestamp) { + int result = super.compareTo(theTimestamp); + if (result == 0) { + int thisNano = this.getNanos(); + int thatNano = theTimestamp.getNanos(); + if (thisNano > thatNano) { + return 1; + } else if (thisNano == thatNano) { + return 0; + } else { + return -1; + } + } + return result; + } + + /** + * Tests to see if this timestamp is equal to a supplied object. + * + * @param theObject + * @return true if this Timestamp object is equal to the supplied Timestamp + * object false if the object is not a Timestamp object or if the + * object is a Timestamp but represents a different instant in time + */ + @Override + public boolean equals(Object theObject) { + if (theObject instanceof Timestamp) { + return equals((Timestamp) theObject); + } + return false; + } + + /** + * Tests to see if this timestamp is equal to a supplied timestamp. + * + * @param theTimestamp + * the timestamp to compare with this timestamp object, passed in + * as an Object + * @return true if this Timestamp object is equal to the supplied Timestamp + * object + */ + public boolean equals(Timestamp theTimestamp) { + if (theTimestamp == null) { + return false; + } + return (this.getTime() == theTimestamp.getTime()) + && (this.getNanos() == theTimestamp.getNanos()); + } + + /** + * Gets this Timestamp's nanosecond value + * + * @return The timestamp's nanosecond value, an integer between 0 and + * 999,999,999 + */ + public int getNanos() { + return nanos; + } + + /** + * Returns the time represented by this Timestamp object, as a long value + * containing the number of milliseconds since the Epoch (January 1 1970, + * 00:00:00.000 GMT) + */ + @Override + public long getTime() { + long theTime = super.getTime(); + theTime = theTime + (nanos / 1000000); + return theTime; + } + + /** + * Sets the nanosecond value for this timestamp + * @param n number of nanoseconds + * @throws IllegalArgumentException if number of nanoseconds smaller than 0 + * or greater than 999999999 + */ + public void setNanos(int n) throws IllegalArgumentException { + if ((n < 0) || (n > 999999999)) { + // sql.0=Value out of range + throw new IllegalArgumentException(Messages.getString("sql.0")); //$NON-NLS-1$ + } + nanos = n; + } + + /** + * Sets the time represented by this Timestamp object to the supplied time, + * defined as the number of milliseconds since the Epoch (January 1 1970, + * 00:00:00.000 GMT) + */ + @Override + public void setTime(long theTime) { + /* + * Deal with the nanoseconds value. The supplied time is in milliseconds - + * so we must extract the milliseconds value and multiply by 1000000 to + * get nanoseconds. Things are more complex if theTime value is + * negative, since then the time value is the time before the Epoch but + * the nanoseconds value of the Timestamp must be positive - so we must + * take the "raw" milliseconds value and subtract it from 1000 to get to + * the true nanoseconds value Simultaneously, recalculate the time value + * to the exact nearest second and reset the Date time value + */ + int milliseconds = (int) (theTime % 1000); + theTime = theTime - milliseconds; + if (milliseconds < 0) { + theTime = theTime - 1000; + milliseconds = 1000 + milliseconds; + } + super.setTime(theTime); + setNanos(milliseconds * 1000000); + } + + /** + * Returns the timestamp formatted as a String in the JDBC Timestamp Escape + * format, which is of the form "yyyy-mm-dd hh:mm:ss.nnnnnnnnn" + * + * @return A string representing the instant defined by the Timestamp, in + * JDBC Timestamp escape format + */ + @SuppressWarnings("deprecation") + @Override + public String toString() { + /* + * Use a DecimalFormat to lay out the nanosecond value as a simple + * string of 9 integers, with leading Zeros + */ + DecimalFormat decimalFormat = new DecimalFormat("0"); //$NON-NLS-1$ + decimalFormat.setMinimumIntegerDigits(9); + decimalFormat.setMaximumIntegerDigits(9); + String theNanos = decimalFormat.format(nanos); + theNanos = stripTrailingZeros(theNanos); + + String year = format((getYear() + 1900), 4); + String month = format((getMonth() + 1), 2); + String date = format(getDate(), 2); + String hours = format(getHours(), 2); + String minutes = format(getMinutes(), 2); + String seconds = format(getSeconds(), 2); + + return year + '-' + month + '-' + date + ' ' + hours + ':' + minutes + + ':' + seconds + '.' + theNanos; + } + + /* + * Private method to format the time + */ + private String format(int date, int digits) { + StringBuilder dateStringBuffer = new StringBuilder(String.valueOf(date)); + while (dateStringBuffer.length() < digits) { + dateStringBuffer = dateStringBuffer.insert(0,'0'); + } + return dateStringBuffer.toString(); + } + + /* + * Private method to strip trailing '0' characters from a string. @param + * inputString the starting string @return a string with the trailing zeros + * stripped - will leave a single 0 at the beginning of the string + */ + private String stripTrailingZeros(String inputString) { + String finalString; + + int i; + for (i = inputString.length(); i > 0; i--) { + if (inputString.charAt(i - 1) != '0') { + break; + } + /* + * If the string has a 0 as its first character, return a string + * with a single '0' + */ + if (i == 1) { + return "0"; //$NON-NLS-1$ + } + } + + finalString = inputString.substring(0, i); + return finalString; + } + + /** + * Creates a Timestamp object with a time value equal to the time specified + * by a supplied String holding the time in JDBC timestamp escape format, + * which is of the form "yyyy-mm-dd hh:mm:ss.nnnnnnnnn" + * + * @param s + * the String containing a time in JDBC timestamp escape format + * @return A timestamp object with time value as defined by the supplied + * String + * @throws IllegalArgumentException if the provided String is null + */ + public static Timestamp valueOf(String s) throws IllegalArgumentException { + if (s == null) { + // sql.3=Argument cannot be null + throw new IllegalArgumentException(Messages.getString("sql.3")); //$NON-NLS-1$ + } + + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ + ParsePosition pp = new ParsePosition(0); + + /* + * First parse out the yyyy-MM-dd HH:mm:ss component of the String into + * a Date object using the SimpleDateFormat. This should stop after the + * seconds value, according to the definition of SimpleDateFormat.parse, + * with the ParsePosition indicating the index of the "." which should + * precede the nanoseconds value + */ + Date theDate; + try { + theDate = df.parse(s, pp); + } catch (Exception e) { + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + + if (theDate == null) { + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + + /* + * If we get here, the Date part of the string was OK - now for the + * nanoseconds value. Strictly, this requires the remaining part of the + * String to look like ".nnnnnnnnn". However, we accept anything with a + * '.' followed by 1 to 9 digits - we also accept nothing (no fractions + * of a second). Anything else is interpreted as incorrect format which + * will generate an IllegalArgumentException + */ + int position = pp.getIndex(); + int remaining = s.length() - position; + int theNanos; + + if (remaining == 0) { + // First, allow for the case where no fraction of a second is given: + theNanos = 0; + } else { + /* + * Case where fraction of a second is specified: Require 1 character + * plus the "." in the remaining part of the string... + */ + if ((s.length() - position) < ".n".length()) { //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + + /* + * If we're strict, we should not allow any EXTRA characters after + * the 9 digits + */ + if ((s.length() - position) > ".nnnnnnnnn".length()) { //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + + // Require the next character to be a "." + if (s.charAt(position) != '.') { + // sql.4=Bad input string format: expected '.' not {0} + throw new NumberFormatException(Messages.getString("sql.4", s.charAt(position))); //$NON-NLS-1$ + } + // Get the length of the number string - need to account for the '.' + int nanoLength = s.length() - position - 1; + + // Get the 9 characters following the "." as an integer + String theNanoString = s.substring(position + 1, position + 1 + + nanoLength); + /* + * We must adjust for the cases where the nanos String was not 9 + * characters long by padding out with zeros + */ + theNanoString = theNanoString + "000000000"; //$NON-NLS-1$ + theNanoString = theNanoString.substring(0, 9); + + try { + theNanos = Integer.parseInt(theNanoString); + } catch (Exception e) { + // If we get here, the string was not a number + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + } + + if (theNanos < 0 || theNanos > 999999999) { + throw new IllegalArgumentException(Messages.getString("sql.2")); //$NON-NLS-1$ + } + + Timestamp theTimestamp = new Timestamp(theDate.getTime()); + theTimestamp.setNanos(theNanos); + + return theTimestamp; + } +} diff --git a/sql/src/main/java/java/sql/Types.java b/sql/src/main/java/java/sql/Types.java new file mode 100644 index 0000000..5e9aa4c --- /dev/null +++ b/sql/src/main/java/java/sql/Types.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.sql; + +/** + * A class which defines constants used to identify generic SQL types, also + * called JDBC types. The type constant values are equivalent to those in XOPEN. + */ +public class Types { + + /* + * Private constructor to prevent instantiation. + */ + private Types() { + super(); + } + + /** + * The type code that identifies the SQL type ARRAY. + */ + public static final int ARRAY = 2003; + + /** + * The type code that identifies the SQL type BIGINT. + */ + public static final int BIGINT = -5; + + /** + * The type code that identifies the SQL type BINARY. + */ + public static final int BINARY = -2; + + /** + * The type code that identifies the SQL type BIT. + */ + public static final int BIT = -7; + + /** + * The type code that identifies the SQL type BLOB. + */ + public static final int BLOB = 2004; + + /** + * The type code that identifies the SQL type BOOLEAN. + */ + public static final int BOOLEAN = 16; + + /** + * The type code that identifies the SQL type CHAR. + */ + public static final int CHAR = 1; + + /** + * The type code that identifies the SQL type CLOB. + */ + public static final int CLOB = 2005; + + /** + * The type code that identifies the SQL type DATALINK. + */ + public static final int DATALINK = 70; + + /** + * The type code that identifies the SQL type DATE. + */ + public static final int DATE = 91; + + /** + * The type code that identifies the SQL type DECIMAL. + */ + public static final int DECIMAL = 3; + + /** + * The type code that identifies the SQL type DISTINCT. + */ + public static final int DISTINCT = 2001; + + /** + * The type code that identifies the SQL type DOUBLE. + */ + public static final int DOUBLE = 8; + + /** + * The type code that identifies the SQL type FLOAT. + */ + public static final int FLOAT = 6; + + /** + * The type code that identifies the SQL type INTEGER. + */ + public static final int INTEGER = 4; + + /** + * The type code that identifies the SQL type JAVA_OBJECT. + */ + public static final int JAVA_OBJECT = 2000; + + /** + * The type code that identifies the SQL type LONGVARBINARY. + */ + public static final int LONGVARBINARY = -4; + + /** + * The type code that identifies the SQL type LONGVARCHAR. + */ + public static final int LONGVARCHAR = -1; + + /** + * The type code that identifies the SQL type NULL. + */ + public static final int NULL = 0; + + /** + * The type code that identifies the SQL type NUMERIC. + */ + public static final int NUMERIC = 2; + + /** + * The type code that identifies that the SQL type is database specific and + * is mapped to a Java object, accessed via the methods + * <code>getObject</code> and <code>setObject</code>. + */ + public static final int OTHER = 1111; + + /** + * The type code that identifies the SQL type REAL. + */ + public static final int REAL = 7; + + /** + * The type code that identifies the SQL type REF. + */ + public static final int REF = 2006; + + /** + * The type code that identifies the SQL type SMALLINT. + */ + public static final int SMALLINT = 5; + + /** + * The type code that identifies the SQL type STRUCT. + */ + public static final int STRUCT = 2002; + + /** + * The type code that identifies the SQL type TIME. + */ + public static final int TIME = 92; + + /** + * The type code that identifies the SQL type TIMESTAMP. + */ + public static final int TIMESTAMP = 93; + + /** + * The type code that identifies the SQL type TINYINT. + */ + public static final int TINYINT = -6; + + /** + * The type code that identifies the SQL type VARBINARY. + */ + public static final int VARBINARY = -3; + + /** + * The type code that identifies the SQL type VARCHAR. + */ + public static final int VARCHAR = 12; +} diff --git a/sql/src/main/java/java/sql/package.html b/sql/src/main/java/java/sql/package.html new file mode 100644 index 0000000..e46f170 --- /dev/null +++ b/sql/src/main/java/java/sql/package.html @@ -0,0 +1,7 @@ +<html> + <body> + <p> + Provides a standard interface for accessing SQL-based databases. + <p> + </body> +</html>
\ No newline at end of file diff --git a/sql/src/main/java/javax/sql/ConnectionEvent.java b/sql/src/main/java/javax/sql/ConnectionEvent.java new file mode 100644 index 0000000..e8ec7c3 --- /dev/null +++ b/sql/src/main/java/javax/sql/ConnectionEvent.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.util.EventObject; +import java.sql.SQLException; +import java.io.Serializable; + +/** + * An Event object which is sent when specific events happen on a + * PooledConnection object. The events involved are when the application closing + * the PooledConnection and when an error occurs in the PooledConnection. + */ +public class ConnectionEvent extends EventObject implements Serializable { + + private static final long serialVersionUID = -4843217645290030002L; + + private SQLException theSQLException; + + /** + * Creates a connection event initialized with a supplied PooledConnection. + * + * @param theConnection + * the PooledConnection + */ + public ConnectionEvent(PooledConnection theConnection) { + super(theConnection); + } + + /** + * Creates a ConnectionEvent initialized with a supplied PooledConnection + * and with a supplied SQLException indicating that an error has occurred + * within the PooledConnection. + * + * @param theConnection + * the PooledConnection + * @param theException + * the SQLException holding information about the error that has + * occurred, which is about to be returned to the application. + */ + public ConnectionEvent(PooledConnection theConnection, + SQLException theException) { + super(theConnection); + theSQLException = theException; + } + + /** + * Gets the SQLException which holds information about the error which + * occurred in the PooledConnection. + * + * @return an SQLException containing information about the error. May be + * null if no error has occurred. + */ + public SQLException getSQLException() { + return theSQLException; + } +} diff --git a/sql/src/main/java/javax/sql/ConnectionEventListener.java b/sql/src/main/java/javax/sql/ConnectionEventListener.java new file mode 100644 index 0000000..7156558 --- /dev/null +++ b/sql/src/main/java/javax/sql/ConnectionEventListener.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.util.EventListener; + +/** + * An interface used to receive events generated by a + * <code>PooledConnection</code>. + * <p> + * This interface would typically be implemented by a component which implements + * Connection Pooling (a Connection Pool Manager). A Connection will signal + * events to a ConnectionEventListener either when the application closes a + * Connection it has been using or when a significant error occurs while the + * Connection is being used, where the Connection should not be used again. + * <p> + * The Connection Pool Manager can return closed Connections to the Pool for + * later reuse. Connections experiencing an error should be discarded. + * + */ +public interface ConnectionEventListener extends EventListener { + + /** + * Notifies the ConnectionEventListener that an application has called the + * <code>close</code> method on a pooled Connection. + * + * @param theEvent + * a ConnectionEvent containing detail about the source of the + * event. + */ + public void connectionClosed(ConnectionEvent theEvent); + + /** + * Notifies the ConnectionEventListener that an error has occurred while a + * PooledConnection was being used and that the PooledConnection can no + * longer be used for work. This notification is done just before the + * SQLException passed in the event message is thrown to the application. + * + * @param theEvent + * a ConnectionEvent containing detail about the source of the + * event and the SQLException that has occurred. + */ + public void connectionErrorOccurred(ConnectionEvent theEvent); +} diff --git a/sql/src/main/java/javax/sql/ConnectionPoolDataSource.java b/sql/src/main/java/javax/sql/ConnectionPoolDataSource.java new file mode 100644 index 0000000..5be75d9 --- /dev/null +++ b/sql/src/main/java/javax/sql/ConnectionPoolDataSource.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; +import java.io.PrintWriter; + +/** + * An interface for the creation of PooledConnection objects. Used internally + * within the package. + * <p> + * A class which implements the ConnectionPoolDataSource interface is typically + * registered with a JNDI naming service directory and is retrieved from there + * by name. + */ +public interface ConnectionPoolDataSource { + + /** + * Gets the Login Timeout value for this ConnectionPoolDataSource. The Login + * Timeout is the maximum time in seconds that the ConnectionPoolDataSource + * will wait when opening a connection to a database. A Timeout value of 0 + * implies either the system default timeout value (if there is one) or that + * there is no timeout. The default value for the Login Timeout is 0. + * + * @return the Login Timeout value in seconds. + * @throws SQLException + * if there is a problem accessing the database. + */ + public int getLoginTimeout() throws SQLException; + + /** + * Gets the Log Writer for this ConnectionPoolDataSource. + * <p> + * The Log Writer is a stream to which all log and trace messages are sent + * from this ConnectionPoolDataSource. The Log Writer can be null, in which + * case, log and trace capture is disabled. The default value for the Log + * Writer when an ConnectionPoolDataSource is created is null. Note that the + * Log Writer for an ConnectionPoolDataSource is not the same as the Log + * Writer used by a <code>DriverManager</code>. + * + * @return a PrintWriter which is the Log Writer for this + * ConnectionPoolDataSource. Can be null, in which case log writing + * is disabled for this ConnectionPoolDataSource. + * @throws SQLException + * if there is a problem accessing the database. + */ + public PrintWriter getLogWriter() throws SQLException; + + /** + * Create a connection to a database which can then be used as a pooled + * connection. + * + * @return a PooledConnection which represents the connection to the + * database + * @throws SQLException + * if there is a problem accessing the database. + */ + public PooledConnection getPooledConnection() throws SQLException; + + /** + * Create a connection to a database, using a supplied Username and + * Password, which can then be used as a pooled connection. + * + * @param theUser + * a String containing a User Name for the database + * @param thePassword + * a String containing the Password for the user identified by + * <code>theUser</code> + * @return a PooledConnection which represents the connection to the + * database + * @throws SQLException + * if there is a problem accessing the database. + */ + public PooledConnection getPooledConnection(String theUser, + String thePassword) throws SQLException; + + /** + * Sets the Login Timeout value for this ConnectionPoolDataSource. The Login + * Timeout is the maximum time in seconds that the ConnectionPoolDataSource + * will wait when opening a connection to a database. A Timeout value of 0 + * implies either the system default timeout value (if there is one) or that + * there is no timeout. The default value for the Login Timeout is 0. + * + * @param theTimeout + * the new Login Timeout value in seconds. + * @throws SQLException + * if there is a problem accessing the database. + */ + public void setLoginTimeout(int theTimeout) throws SQLException; + + /** + * Sets the Log Writer for this ConnectionPoolDataSource. + * <p> + * The Log Writer is a stream to which all log and trace messages are sent + * from this ConnectionPoolDataSource. The Log Writer can be null, in which + * case, log and trace capture is disabled. The default value for the Log + * Writer when an ConnectionPoolDataSource is created is null. Note that the + * Log Writer for an ConnectionPoolDataSource is not the same as the Log + * Writer used by a <code>DriverManager</code>. + * + * @param theWriter + * a PrintWriter to use as the Log Writer for this + * ConnectionPoolDataSource. + * @throws SQLException + * if there is a problem accessing the database. + */ + public void setLogWriter(PrintWriter theWriter) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/DataSource.java b/sql/src/main/java/javax/sql/DataSource.java new file mode 100644 index 0000000..cd3e0a3 --- /dev/null +++ b/sql/src/main/java/javax/sql/DataSource.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; +import java.sql.Connection; +import java.io.PrintWriter; + +/** + * An interface for the creation of Connection objects which represent a + * connection to a database. This interface is an alternative to the + * <code>java.sql.DriverManager</code>. + * <p> + * A class which implements the DataSource interface is typically registered + * with a JNDI naming service directory and is retrieved from there by name. + * <p> + * The DataSource interface is typically implemented by the writer of a JDBC + * driver. There are three variants of the DataSource interface, which produce + * Connections with differing characteristics: + * <ol> + * <li>Standard DataSource, which produces standard Connection objects with no + * special features.</li> + * <li>Connection Pool DataSource, which produces PooledConnection objects + * which are able to participate in connection pooling, typically involving a + * connection pooling manager as an intermediary between applications and the + * database.</li> + * <li>Distributed transaction DataSource ("XADataSource"), which produces + * XAConnection objects which can be used to handle distributed transactions and + * which typically involve a transaction manager component in the system. + * XAConnection objects also typically provide connection pooling capabilities + * as well as distributed transaction capabilities. </li> + * </ol> + * <p> + * Note that a JDBC driver which is accessed via the DataSource interface is + * loaded via a JNDI lookup process. A driver loaded in this way does not + * register itself with the <code>DriverManager</code>. + */ +public interface DataSource { + + /** + * Creates a connection to the database represented by this DataSource. + * + * @return a Connection object which is a connection to the database. + * @throws SQLException + * if there is a problem accessing the database. + */ + public Connection getConnection() throws SQLException; + + /** + * Creates a connection to the database represented by this DataSource, + * using a supplied Username and Password,. + * + * @param theUsername + * a String containing a User Name for the database + * @param thePassword + * a String containing the Password for the user identified by + * <code>theUsername</code> + * @return a Connection object which is a connection to the database. + * @throws SQLException + * if there is a problem accessing the database. + */ + public Connection getConnection(String theUsername, String thePassword) + throws SQLException; + + /** + * Gets the Login Timeout value for this DataSource. The Login Timeout is + * the maximum time in seconds that the DataSource will wait when opening a + * connection to a database. A Timeout value of 0 implies either the system + * default timeout value (if there is one) or that there is no timeout. The + * default value for the Login Timeout is 0. + * + * @return the Login Timeout value in seconds. + * @throws SQLException + * if there is a problem accessing the database. + */ + public int getLoginTimeout() throws SQLException; + + /** + * Gets the Log Writer for this DataSource. + * <p> + * The Log Writer is a stream to which all log and trace messages are sent + * from this DataSource. The Log Writer can be null, in which case, log and + * trace capture is disabled. The default value for the Log Writer when an + * DataSource is created is null. Note that the Log Writer for an DataSource + * is not the same as the Log Writer used by a <code>DriverManager</code>. + * + * @return a PrintWriter which is the Log Writer for this DataSource. Can be + * null, in which case log writing is disabled for this DataSource. + * @throws SQLException + * if there is a problem accessing the database. + */ + public PrintWriter getLogWriter() throws SQLException; + + /** + * Sets the Login Timeout value for this DataSource. The Login Timeout is + * the maximum time in seconds that the DataSource will wait when opening a + * connection to a database. A Timeout value of 0 implies either the system + * default timeout value (if there is one) or that there is no timeout. The + * default value for the Login Timeout is 0. + * + * @param theTimeout + * the new Login Timeout value in seconds. + * @throws SQLException + * if there is a problem accessing the database. + */ + public void setLoginTimeout(int theTimeout) throws SQLException; + + /** + * Sets the Log Writer for this DataSource. + * <p> + * The Log Writer is a stream to which all log and trace messages are sent + * from this DataSource. The Log Writer can be null, in which case, log and + * trace capture is disabled. The default value for the Log Writer when an + * DataSource is created is null. Note that the Log Writer for an DataSource + * is not the same as the Log Writer used by a <code>DriverManager</code>. + * + * @param theWriter + * a PrintWriter to use as the Log Writer for this DataSource. + * @throws SQLException + * if there is a problem accessing the database. + */ + public void setLogWriter(PrintWriter theWriter) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/PooledConnection.java b/sql/src/main/java/javax/sql/PooledConnection.java new file mode 100644 index 0000000..50f7ae9 --- /dev/null +++ b/sql/src/main/java/javax/sql/PooledConnection.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; +import java.sql.Connection; + +/** + * An interface which provides facilities for handling connections to a database + * which are pooled. + * <p> + * Typically, a PooledConnection is recycled when it is no longer required by an + * application, rather than being closed and discarded. The reason for treating + * connections in this way is that it can be an expensive process both to + * establish a connection to a database and to destroy the connection. Reusing + * connections through a pool is a way of improving system performance and + * reducing overhead. + * <p> + * It is not intended that an application use the PooledConnection interface + * directly. The PooledConnection interface is intended for use by a component + * called a Connection Pool Manager, typically part of the infrastructure that + * supports use of the database by applications. + * <p> + * Applications obtain connections to the database by calling the + * <code>DataSource.getConnection</code> method. Under the covers, the + * Connection Pool Manager will get a PooledConnection object from its + * connection pool and passes back a Connection object that wraps or references + * the PooledConnection object. A new PooledConnection object will only be + * created if the pool is empty. + * <p> + * When the application is finished using a PooledConnection, the application + * calls the <code>Connection.close</code> method. The Connection Pool Manager + * is notified via a ConnectionEvent from the Connection that this has happened + * (the Pool Manager registers itself with the Connection before the Connection + * is given to the application). The Pool Manager removes the underlying + * PooledConnection object from the Connection and returns it to the pool for + * reuse - the PooledConnection is thus recycled rather than being destroyed. + * <p> + * The connection to the database represented by the PooledConnection is kept + * open until the PooledConnection object itself is deactivated by the + * Connection Pool Manager, which calls the <code>PooledConnection.close</code> + * method. This is typically done if there are too many inactive connections in + * the pool, if the PooledConnection encounters a problem that makes it unusable + * or if the whole system is being shut down. + * + */ +public interface PooledConnection { + + /** + * Registers the supplied ConnectionEventListener with this + * PooledConnection. Once registered, the ConnectionEventListener will + * receive ConnectionEvent events when they occur in the PooledConnection. + * + * @param theListener + * an object which implements the ConnectionEventListener + * interface. + */ + public void addConnectionEventListener(ConnectionEventListener theListener); + + /** + * Closes the connection to the database held by this PooledConnection. This + * method should not be called directly by application code - it is intended + * for use by the Connection Pool manager component. + * + * @throws SQLException + * if there is a problem accessing the database. + */ + public void close() throws SQLException; + + /** + * Creates a connection to the database. This method is typically called by + * the Connection Pool manager when an application invokes the method + * <code>DataSource.getConnection</code> and there are no PooledConnection + * objects available in the connection pool. + * + * @return a Connection object that is a handle to this PooledConnection + * object. + * @throws SQLException + * if there is a problem accessing the database. + */ + public Connection getConnection() throws SQLException; + + /** + * Deregister the supplied ConnectionEventListener from this + * PooledConnection. Once deregistered, the ConnectionEventListener will not + * longer receive events occurring in the PooledConnection. + * + * @param theListener + * an object which implements the ConnectionEventListener + * interface. This object should have previously been registered + * with the PooledConnection using the + * <code>addConnectionEventListener</code> method. + */ + public void removeConnectionEventListener( + ConnectionEventListener theListener); +} diff --git a/sql/src/main/java/javax/sql/RowSet.java b/sql/src/main/java/javax/sql/RowSet.java new file mode 100644 index 0000000..2794ff2 --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSet.java @@ -0,0 +1,856 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.Ref; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Map; +import java.io.InputStream; +import java.io.Reader; +import java.util.Calendar; +import java.math.BigDecimal; + +/** + * A RowSet is an interface which provides access to data being sent from/to a + * database and which extends the functionality of ResultSet into a form that + * can be used as a JavaBeans component, perhaps being used in a visual + * programming environment. + * <p> + * Facilities are provided for get/set of properties relating to the Database + * and the SQL Command and for getting/setting data within the Rows represented + * by the RowSet. The RowSet supports JavaBeans events so that other components + * in an application can be informed when various changes happen to the RowSet, + * such as changes in data values. + * <p> + * RowSet is implemented as a layer on top of the remainder of the JDBC API. A + * RowSet may be <i>connected</i> where it maintains a connection to the + * database throughout its lifecycle. A RowSet may be <i>disconnected</i> where + * it establishes a connection to the database, gets data and then closes the + * connection. Updates to a disconnected RowSet can be made and later send back + * the changes to the database, but this requires the RowSet to first reconnect + * to the database before the changes are sent back. + * <p> + * Disconnected RowSets may make use of RowSetReaders to populate the RowSet + * with data, possibly from a non-relational database source. Disconnected + * RowSets may also use RowSetWriters to send data back to the underlying data + * store. There is considerable freedom in the way that RowSetReaders and + * RowSetWriters are implemented to get and store data. + */ +public interface RowSet extends ResultSet { + + /** + * Registers a supplied RowSetListener with this RowSet. Once registered, + * the RowSetListener is notified of events generated by the RowSet. + * + * @param theListener + * an object which implements the <code>rowSetListener</code> + * interface. + */ + public void addRowSetListener(RowSetListener theListener); + + /** + * Clears the parameters previously set for this RowSet. + * <p> + * Parameter values apply to repeated use of a RowSet object. Setting a new + * value for a parameter clears its previous value. + * <code>clearParameters</code> clears the values for all parameters with + * one method call. + * + * @throws SQLException + * if a problem occurs accessing the database + */ + public void clearParameters() throws SQLException; + + /** + * Fetches data for this RowSet. If successful, any existing data for the + * RowSet is discarded and the metadata for the rowset is set. + * <p> + * Data is retrieved connects to the database and executes a Command. This + * requires some or all of the following properties to be set: url, data + * source name, user name, password, transaction isolation, type map ; plus + * some or all of the properties: command, read only, maximum field size, + * maximum rows, escape processing, and query timeout. + * <p> + * The RowSet may use a RowSetReader to access the database - in this case a + * reader must be registered with the RowSet and the RowSet will then invoke + * the <code>readData</code> method on the reader to fetch the data. + * + * @throws SQLException + * if a problem occurs accessing the database or if the + * properties needed to access the database have not been set + */ + public void execute() throws SQLException; + + /** + * Gets the RowSet's Command property. + * + * @return a string containing the RowSet's Command property - this is an + * SQL Query which can be executed to fetch data into the RowSet. + */ + public String getCommand(); + + /** + * Gets the name of the datasource for this RowSet. + * + * @return a String containing the name of the datasource. + */ + public String getDataSourceName(); + + /** + * Reports if escape processing is enabled for this RowSet. + * <p> + * If <code>true</code> (the default) the driver will automatically + * perform escape code processing on SQL statements prior to them being sent + * to the database. + * + * @return true if escape processing is enabled, false otherwise. + * @throws SQLException + * if a problem occurs accessing the database + */ + public boolean getEscapeProcessing() throws SQLException; + + /** + * Gets the maximum number of bytes that can be returned for column values + * which are of types BINARY, VARBINARY, LONGVARBINARYBINARY, CHAR, VARCHAR, + * or LONGVARCHAR. Excess data is silently discarded if the number is + * exceeded. + * + * @return the current maximum size in bytes. 0 means no limit + * @throws SQLException + * if a problem occurs accessing the database + */ + public int getMaxFieldSize() throws SQLException; + + /** + * Gets the maximum number of rows for this RowSet. Excess rows are + * discarded silently if the limit is exceeded. + * + * @return the previous maximum number of rows. 0 implies no limit. + * @throws SQLException + * if a problem occurs accessing the database + */ + public int getMaxRows() throws SQLException; + + /** + * Gets the value of the password property for this RowSet. This property + * is used when making a connection to the database and should be set before + * invoking the <code>execute</code> method. + * + * @return a String containing the value of the password property. + */ + public String getPassword(); + + /** + * Gets the Timeout for the driver when executing a Query operation. + * <p> + * If a Query takes longer than the Timeout, an exception is thrown. + * + * @return the Timeout value in seconds. + * @throws SQLException + * if an error occurs accessing the database. + */ + public int getQueryTimeout() throws SQLException; + + /** + * Gets the transaction isolation property setting for this RowSet. + * + * @return an integer holding the current transaction isolation setting. One + * of: one of Connection.TRANSACTION_READ_UNCOMMITTED, + * Connection.TRANSACTION_READ_COMMITTED, + * Connection.TRANSACTION_REPEATABLE_READ, + * Connection.TRANSACTION_SERIALIZABLE + */ + public int getTransactionIsolation(); + + /** + * Gets the custom mapping of SQL types for this RowSet, if any. + * + * @return a Map holding the custom mappings of SQL types to Java classes for + * this RowSet. By default, the Map is empty. + * @throws SQLException + * if an error occurs accessing the database. + */ + public Map<String, Class<?>> getTypeMap() throws SQLException; + + /** + * Gets the URL property value for this RowSet. If there is no DataSource + * object specified, the RowSet uses the URL to establish a connection to + * the database. The default value for the URL is null. + * + * @return a String holding the value of the URL property. + * @throws SQLException + * if an error occurs accessing the database. + */ + public String getUrl() throws SQLException; + + /** + * Gets the value of the Username property for this RowSet. The Username is + * used when establishing a connection to the database and should be set + * before the <code>execute</code> method is invoked. + * + * @return a String holing the value of the Username property. + */ + public String getUsername(); + + /** + * Reports if this RowSet is read only. + * + * @return true if this RowSet is read only, false if it is updateable. + */ + public boolean isReadOnly(); + + /** + * Removes a specified RowSetListener object from the set of listeners which + * will be notified of events by this RowSet. + * + * @param theListener + * the RowSetListener to remove from the set of listeners for + * this RowSet. + */ + public void removeRowSetListener(RowSetListener theListener); + + /** + * Sets the specified ARRAY parameter in the RowSet command with the + * supplied java.sql.Array value. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theArray + * the java.sql.Array value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setArray(int parameterIndex, Array theArray) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * ASCII data in the supplied java.io.InputStream value. Data is read from + * the InputStream until end-of-file is reached. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theInputStream + * an InputStream containing the ASCII data to set into the + * parameter value + * @param length + * the length of the data in bytes + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setAsciiStream(int parameterIndex, InputStream theInputStream, + int length) throws SQLException; + + /** + * Sets the value of the specified SQL NUMERIC parameter in the RowSet + * command with the data in the supplied java.math.BigDecimal value. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theBigDecimal + * the BigDecimal containing the value + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setBigDecimal(int parameterIndex, BigDecimal theBigDecimal) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * binary data in the supplied java.io.InputStream value. Data is read from + * the InputStream until end-of-file is reached. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theInputStream + * an InputStream containing the binary data to set into the + * parameter value + * @param length + * the length of the data in bytes + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setBinaryStream(int parameterIndex, InputStream theInputStream, + int length) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * value of a supplied java.sql.Blob. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theBlob + * the Blob value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setBlob(int parameterIndex, Blob theBlob) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to the + * supplied boolean. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theBoolean + * the boolean value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setBoolean(int parameterIndex, boolean theBoolean) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to the + * supplied byte value. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theByte + * the byte value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setByte(int parameterIndex, byte theByte) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to the + * supplied byte array value. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theByteArray + * the array of bytes to set into the parameter. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setBytes(int parameterIndex, byte[] theByteArray) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to the + * sequence of Unicode characters carried by the supplied java.io.Reader. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theReader + * the Reader which contains the Unicode data to set into the + * parameter + * @param length + * the length of the data in the Reader in characters + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setCharacterStream(int parameterIndex, Reader theReader, + int length) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * value of a supplied java.sql.Clob. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theClob + * the Clob value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setClob(int parameterIndex, Clob theClob) throws SQLException; + + /** + * Sets the Command property for this RowSet - the command is an SQL Query + * which runs when the <code>execute</code> method is invoked. This + * property is optional for datasources that do not support commands. + * + * @param cmd + * a String containing the SQL Query. Can be null. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setCommand(String cmd) throws SQLException; + + /** + * Sets the concurrency property of this RowSet. The default value is + * ResultSet.CONCUR_READ_ONLY. + * + * @param concurrency + * the new concurrency value - one of: ResultSet.CONCUR_READ_ONLY + * or ResultSet.CONCUR_UPDATABLE + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setConcurrency(int concurrency) throws SQLException; + + /** + * Sets the Data Source Name property for the RowSet. + * <p> + * The Data Source Name can be used to find a <code>DataSource</code> + * which has been registered with a naming service - the DataSource can then + * be used to create a connection to the database. + * + * @param name + * a String with the new Data Source Name. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setDataSourceName(String name) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * value of a supplied java.sql.Date. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theDate + * the Date to use + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setDate(int parameterIndex, Date theDate) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * value of a supplied java.sql.Date, where the conversion of the Date to an + * SQL DATE value is calculated using a supplied Calendar. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theDate + * the Date to use + * @param theCalendar + * the Calendar to use in converting the Date to an SQL DATE value + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setDate(int parameterIndex, Date theDate, Calendar theCalendar) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * supplied double. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theDouble + * the double value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setDouble(int parameterIndex, double theDouble) + throws SQLException; + + /** + * Sets the Escape Processing status for this RowSet. If escape processing + * is on, the driver performs escape substitution before sending an SQL + * command to the database. The default value for escape processing is on. + * + * @param enable + * true to enable Escape Processing, false to turn it off. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setEscapeProcessing(boolean enable) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * supplied float. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theFloat + * the float value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setFloat(int parameterIndex, float theFloat) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * supplied integer. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theInteger + * the integer value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setInt(int parameterIndex, int theInteger) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command with the + * supplied long. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theLong + * the long value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setLong(int parameterIndex, long theLong) throws SQLException; + + /** + * Sets the maximum number of bytes which can be returned for a column value + * where the column type BINARY, VARBINARY, LONGVARBINARYBINARY, CHAR, + * VARCHAR, or LONGVARCHAR. Data which exceeds this limit is silently + * discarded. For portability, a value greater than 256 is recommended. + * + * @param max + * the maximum size of the returned column value in bytes. 0 + * means unlimited. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setMaxFieldSize(int max) throws SQLException; + + /** + * Sets the maximum number of rows which can be held by the RowSet. Any + * additional rows are silently discarded. + * + * @param max + * the maximum number of rows which can be held in the RowSet. 0 + * means no limit. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setMaxRows(int max) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to SQL + * NULL. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param sqlType + * the type of the parameter, as defined by java.sql.Types. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setNull(int parameterIndex, int sqlType) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to SQL + * NULL. This form of the <code>setNull</code> method should be used for + * User Defined Types and REF parameters. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param sqlType + * the type of the parameter, as defined by java.sql.Types. + * @param typeName + * the fully qualified name of an SQL User Defined Type or the + * name of the SQL structured type referenced by a REF type. + * Ignored if the sqlType is not a UDT or REF type. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setNull(int parameterIndex, int sqlType, String typeName) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied Java object. + * <p> + * The JDBC specification provides a standard mapping for Java objects to + * SQL data types. Database specific types can be mapped by JDBC driver + * specific Java types. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theObject + * the Java object containing the data value. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setObject(int parameterIndex, Object theObject) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied Java object. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theObject + * the Java object containing the data value. + * @param targetSqlType + * the SQL type to send to the database, as defined in + * java.sql.Types. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setObject(int parameterIndex, Object theObject, + int targetSqlType) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied Java object. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theObject + * the Java object containing the data value. + * @param targetSqlType + * the SQL type to send to the database, as defined in + * java.sql.Types. + * @param scale + * the number of digits after the decimal point, for + * java.sql.Types.DECIMAL and java.sql.Types.NUMERIC types. + * Ignored for all other types. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setObject(int parameterIndex, Object theObject, + int targetSqlType, int scale) throws SQLException; + + /** + * Sets the database Password for this RowSet. + * + * @param password + * a string holding the new password + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setPassword(String password) throws SQLException; + + /** + * Sets the Timeout value for this RowSet. The timeout is the maximum time + * that the driver will wait while executing a command - after this time, an + * SQLException is thrown. + * + * @param seconds + * the number of seconds for the Timeout. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setQueryTimeout(int seconds) throws SQLException; + + /** + * Sets whether the RowSet is read only or is updateable. + * + * @param readOnly + * true to set the RowSet to readonly state, false to allow + * updates. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setReadOnly(boolean readOnly) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied java.sql.Ref. This is sent to the database as an SQL REF value. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theRef + * the Ref value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setRef(int parameterIndex, Ref theRef) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied short integer. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theShort + * the short value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setShort(int parameterIndex, short theShort) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied String. The String is placed into the database as a VARCHAR or + * LONGVARCHAR SQL value, depending on the database limits for the length of + * VARCHAR values. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theString + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setString(int parameterIndex, String theString) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied java.sql.Time, converting to an SQL TIME value using the system + * default Calendar. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theTime + * the Time value to set + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTime(int parameterIndex, Time theTime) throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied java.sql.Time, converting to an SQL TIME value using a supplied + * Calendar. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theTime + * the Time value to set + * @param theCalendar + * the Calendar to use in the conversion operation + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTime(int parameterIndex, Time theTime, Calendar theCalendar) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied java.sql.Timestamp, converting to an SQL TIMESTAMP value using + * the system default Calendar. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theTimestamp + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTimestamp(int parameterIndex, Timestamp theTimestamp) + throws SQLException; + + /** + * Sets the value of the specified parameter in the RowSet command to a + * supplied java.sql.Timestamp converting to an SQL TIMESTAMP value using a + * supplied Calendar. + * + * @param parameterIndex + * index of the parameter to set, where the first parameter has + * index = 1. + * @param theTimestamp + * @param theCalendar + * the Calendar to use in the conversion operation + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTimestamp(int parameterIndex, Timestamp theTimestamp, + Calendar theCalendar) throws SQLException; + + /** + * Updates the target instance's transaction isolation level to one of a + * discrete set of possible values. + * + * @param level + * the new transaction isolation level. One of: + * Connection.TRANSACTION_READ_UNCOMMITTED, + * Connection.TRANSACTION_READ_COMMITTED, + * Connection.TRANSACTION_REPEATABLE_READ, or + * Connection.TRANSACTION_SERIALIZABLE + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTransactionIsolation(int level) throws SQLException; + + /** + * Sets the type of this RowSet. By default, the type is non-scrollable. + * + * @param type + * the new type for the RowSet. One of: + * ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.TYPE_SCROLL_INSENSITIVE, or + * ResultSet.TYPE_SCROLL_SENSITIVE + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setType(int type) throws SQLException; + + /** + * Sets the Map used to map SQL User Defined Types to Java classes. + * + * @param theTypeMap + * a Map which defines the names of SQL UDTs and the Java classes + * to which they are mapped. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setTypeMap(Map<String, Class<?>> theTypeMap) + throws SQLException; + + /** + * Sets the URL used by this RowSet to access the database via a + * <code>DriverManager</code>. The URL is optional - an alternative is to + * use a Data Source Name to create a connection. + * + * @param theURL + * a String containing the URL for the database. Can be null. + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setUrl(String theURL) throws SQLException; + + /** + * Sets the Username property for the RowSet, used to authenticate a + * connection to the database. + * + * @param theUsername + * a String containing the User Name + * @throws SQLException + * if an error occurs accessing the database. + */ + public void setUsername(String theUsername) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/RowSetEvent.java b/sql/src/main/java/javax/sql/RowSetEvent.java new file mode 100644 index 0000000..8682957 --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetEvent.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.util.EventObject; +import java.io.Serializable; + +/** + * An event which is sent when specific events happen to a RowSet object. The + * events are sent to inform registered listeners that changes have occurred to + * the RowSet. The events covered are: + * <ol> + * <li>A single row in the RowSet changes</li> + * <li>The whole set of data in the RowSet changes</li> + * <li>The RowSet cursor position changes</li> + * </ol> + * The event contains a reference to the RowSet object which generated the + * message so that the listeners can extract whatever information they need from + * that reference. + * + */ +public class RowSetEvent extends EventObject implements Serializable { + + private static final long serialVersionUID = -1875450876546332005L; + + /** + * Creates a RowSetEvent object containing a reference to the RowSet object + * that generated the event. Information about the changes that have + * occurred to the RowSet can be extracted from the RowSet using one or more + * of the query methods available on the RowSet. + * + * @param theSource + * the RowSet which generated the event + */ + public RowSetEvent(RowSet theSource) { + super(theSource); + } +} diff --git a/sql/src/main/java/javax/sql/RowSetInternal.java b/sql/src/main/java/javax/sql/RowSetInternal.java new file mode 100644 index 0000000..f224a13 --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetInternal.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; +import java.sql.Connection; +import java.sql.ResultSet; + +/** + * An interface provided by a RowSet object to either a RowSetReader or a + * RowSetWriter, providing facilities to read and update the internal state of + * the RowSet. + */ +public interface RowSetInternal { + + /** + * Gets the Connection associated with this RowSet object. + * + * @return the Connection + * @throws SQLException + * if there is a problem accessing the database. + */ + public Connection getConnection() throws SQLException; + + /** + * Gets the ResultSet that was the original (unmodified) content of the + * RowSet. + * <p> + * The ResultSet cursor is positioned before the first row of data + * + * @return the ResultSet that contained the original data value of the + * RowSet + * @throws SQLException + * if there is a problem accessing the database. + */ + public ResultSet getOriginal() throws SQLException; + + /** + * Gets the original value of the current row only. If the current row did + * not have an original value, then an empty value is returned. + * + * @return a ResultSet containing the value of the current row only. + * @throws SQLException + * if there is a problem accessing the database, or if the + * cursor is not on a valid row (before first, after last or + * pointing to the insert row). + */ + public ResultSet getOriginalRow() throws SQLException; + + /** + * Gets the parameter values that have been set for this RowSet's command. + * + * @return an Object array containing the values of parameters that have + * been set. + * @throws SQLException + * if there is a problem accessing the database. + */ + public Object[] getParams() throws SQLException; + + /** + * Sets RowSetMetaData for this RowSet. The RowSetMetaData is used by a + * RowSetReader to set values giving information about the RowSet's columns. + * + * @param theMetaData + * a RowSetMetaData holding the metadata about the RowSet's + * columns. + * @throws SQLException + * if there is a problem accessing the database. + */ + public void setMetaData(RowSetMetaData theMetaData) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/RowSetListener.java b/sql/src/main/java/javax/sql/RowSetListener.java new file mode 100644 index 0000000..a482d2b --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetListener.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.util.EventListener; + +/** + * An interface used to send notification of events occurring in a RowSet. To + * receive the notification events, an object must implement the RowSetListener + * interface and then register itself with the RowSet of interest using the + * <code>RowSet.addRowSetListener</code> method. + */ +public interface RowSetListener extends EventListener { + + /** + * Notifies the listener that one of the RowSet's rows has changed. + * + * @param theEvent + * a RowSetEvent that contains information about the RowSet + * involved. This information can be used to retrieve information + * about the change, such as the new cursor position. + */ + public void cursorMoved(RowSetEvent theEvent); + + /** + * Notifies the listener that the RowSet's cursor has moved. + * + * @param theEvent + * theEvent a RowSetEvent that contains information about the + * RowSet involved. This information can be used to retrieve + * information about the change, such as the updated data values. + */ + public void rowChanged(RowSetEvent theEvent); + + /** + * Notifies the listener that the RowSet's entire contents have been updated + * (an example is the execution of a command which retrieves new data from + * the database). + * + * @param theEvent + * theEvent a RowSetEvent that contains information about the + * RowSet involved. This information can be used to retrieve + * information about the change, such as the updated rows of + * data. + */ + public void rowSetChanged(RowSetEvent theEvent); +} diff --git a/sql/src/main/java/javax/sql/RowSetMetaData.java b/sql/src/main/java/javax/sql/RowSetMetaData.java new file mode 100644 index 0000000..89d6f7f --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetMetaData.java @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +/** + * An interface which provides facilities for getting information about the + * columns in a RowSet. + * <p> + * RowSetMetaData extends ResultSetMetaData, adding new operations for carrying + * out value sets. + * <p> + * Application code would not normally call this interface directly. It would be + * called internally when <code>RowSet.execute</code> is called. + */ +public interface RowSetMetaData extends ResultSetMetaData { + + /** + * Sets automatic numbering for a specified column in the RowSet. If + * automatic numbering is on, the column is read only. The default value is + * for automatic numbering to be off. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param autoIncrement + * true to set automatic numbering on, false to turn it off. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setAutoIncrement(int columnIndex, boolean autoIncrement) + throws SQLException; + + /** + * Sets the case sensitive property for a specified column in the RowSet. + * The default is that the column is not case sensitive. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param caseSensitive + * true to make the column case sensitive, false to make it not + * case sensitive. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setCaseSensitive(int columnIndex, boolean caseSensitive) + throws SQLException; + + /** + * Sets the Catalog Name for a specified column in the RowSet. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param catalogName + * a string containing the new Catalog Name + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setCatalogName(int columnIndex, String catalogName) + throws SQLException; + + /** + * Sets the number of columns in the Row Set. + * + * @param columnCount + * an integer containing the number of columns in the RowSet. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnCount(int columnCount) throws SQLException; + + /** + * Sets the normal maximum width in characters for a specified column in the + * RowSet. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param displaySize + * an integer with the normal maximum column width in characters + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnDisplaySize(int columnIndex, int displaySize) + throws SQLException; + + /** + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theLabel + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnLabel(int columnIndex, String theLabel) + throws SQLException; + + /** + * Sets the suggested column label for a specified column in the RowSet. + * This label is typically used in displaying or printing the column. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theColumnName + * a string containing the column label + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnName(int columnIndex, String theColumnName) + throws SQLException; + + /** + * Sets the SQL type for a specified column in the RowSet + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theSQLType + * an integer containing the SQL Type, as defined by + * java.sql.Types. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnType(int columnIndex, int theSQLType) + throws SQLException; + + /** + * Sets the Type Name for a specified column in the RowSet, where the data + * type is specific to the datasource. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theTypeName + * a string containing the Type Name for the column + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setColumnTypeName(int columnIndex, String theTypeName) + throws SQLException; + + /** + * Sets whether a specified column is a currency value. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param isCurrency + * true if the column should be treated as a currency value, + * false if it should not be treated as a currency value. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setCurrency(int columnIndex, boolean isCurrency) + throws SQLException; + + /** + * Sets whether a specified column can contain SQL NULL values. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param nullability + * an integer which is one of the following values: + * ResultSetMetaData.columnNoNulls, + * ResultSetMetaData.columnNullable, or + * ResultSetMetaData.columnNullableUnknown + * <p> + * The default value is ResultSetMetaData.columnNullableUnknown + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setNullable(int columnIndex, int nullability) + throws SQLException; + + /** + * Sets the number of decimal digits for a specified column in the RowSet. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param thePrecision + * an integer containing the number of decimal digits + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setPrecision(int columnIndex, int thePrecision) + throws SQLException; + + /** + * For the column specified by <code>columnIndex</code> declares how many + * digits there should be after a decimal point. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theScale + * an integer containing the number of digits after the decimal + * point + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setScale(int columnIndex, int theScale) throws SQLException; + + /** + * Sets the Schema Name for a specified column in the RowSet + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theSchemaName + * a String containing the schema name + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setSchemaName(int columnIndex, String theSchemaName) + throws SQLException; + + /** + * Sets whether a specified column can be used in a search involving a WHERE + * clause. The default value is false. + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param isSearchable + * true of the column can be used in a WHERE clause search, false + * otherwise. + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setSearchable(int columnIndex, boolean isSearchable) + throws SQLException; + + /** + * Sets if a specified column can contain signed numbers + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param isSigned + * true if the column can contain signed numbers, false otherwise + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setSigned(int columnIndex, boolean isSigned) + throws SQLException; + + /** + * Sets the Table Name for a specified column in the RowSet + * + * @param columnIndex + * the index number for the column, where the first column has + * index 1. + * @param theTableName + * a String containing the Table Name for the column + * @throws SQLException + * if a problem occurs accessing the database + */ + public void setTableName(int columnIndex, String theTableName) + throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/RowSetReader.java b/sql/src/main/java/javax/sql/RowSetReader.java new file mode 100644 index 0000000..bc17ded --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetReader.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; + +/** + * An interface which provides functionality for a disconnected RowSet to get + * data from a data source into its rows. The RowSet calls the RowSetReader + * interface when the RowSet's execute method is invoked - a RowSetReader must + * first be registered with the RowSet for this to work. + */ +public interface RowSetReader { + + /** + * Reads new data into the RowSet. The calling RowSet object must itself + * implement the RowSetInternal interface and the RowSetReader must be + * registered as a Reader on the RowSet. + * <p> + * This method adds rows into the calling RowSet. The Reader may invoke any + * of the RowSet's methods except for the <code>execute</code> method + * (calling execute will cause an SQLException to be thrown). However, when + * the Reader calls the RowSet's methods, no events are sent to listeners - + * any listeners are informed by the calling RowSet's execute method once + * the Reader returns from the readData method. + * + * @param theCaller + * must be the calling RowSet object, which must have implemented + * the RowSetInternal interface. + * @throws SQLException + * if a problem occurs accessing the database or if the Reader + * calls the RowSet.execute method. + */ + public void readData(RowSetInternal theCaller) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/RowSetWriter.java b/sql/src/main/java/javax/sql/RowSetWriter.java new file mode 100644 index 0000000..ba95f59 --- /dev/null +++ b/sql/src/main/java/javax/sql/RowSetWriter.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.sql; + +import java.sql.SQLException; + +/** + * An interface which provides functionality for a disconnected RowSet to put + * data updates back to the data source from which the RowSet was originally + * populated. An object implementing this interface is called a Writer. + * <p> + * The Writer must establish a connection to the RowSet's data source before + * writing the data. The RowSet calling this interface must implement the + * RowSetInternal interface. + * <p> + * The Writer may encounter a situation where the updated data being written + * back to the data source has already been updated in the data source. How a + * conflict of this kind is handled is determined by the implementation of the + * Writer. + */ +public interface RowSetWriter { + + /** + * Writes changes in the RowSet associated with this RowSetWriter back to + * its data source. + * + * @param theRowSet + * the RowSet object. This RowSet must a) Implement the + * RowSetInternal interface and b) have have this RowSetWriter + * registered with it and c) must call this method internally + * @return true if the modified data was written, false otherwise (which + * typically implies some form of conflict) + * @throws SQLException + * if a problem occurs accessing the database + */ + public boolean writeData(RowSetInternal theRowSet) throws SQLException; +} diff --git a/sql/src/main/java/javax/sql/package.html b/sql/src/main/java/javax/sql/package.html new file mode 100644 index 0000000..c5d5aee --- /dev/null +++ b/sql/src/main/java/javax/sql/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + Provides extensions to the standard interface for accessing SQL-based + databases. + <p> + </body> +</html>
\ No newline at end of file diff --git a/sql/src/main/java/org/apache/harmony/sql/internal/nls/Messages.java b/sql/src/main/java/org/apache/harmony/sql/internal/nls/Messages.java new file mode 100644 index 0000000..77b669b --- /dev/null +++ b/sql/src/main/java/org/apache/harmony/sql/internal/nls/Messages.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL. + * All changes made to this file manually will be overwritten + * if this tool runs again. Better make changes in the template file. + */ + +package org.apache.harmony.sql.internal.nls; + +import org.apache.harmony.luni.util.MsgHelp; + +/** + * This class retrieves strings from a resource bundle and returns them, + * formatting them with MessageFormat when required. + * <p> + * It is used by the system classes to provide national language support, by + * looking up messages in the <code> + * org.apache.harmony.sql.internal.nls.messages + * </code> + * resource bundle. Note that if this file is not available, or an invalid key + * is looked up, or resource bundle support is not available, the key itself + * will be returned as the associated message. This means that the <em>KEY</em> + * should a reasonable human-readable (english) string. + * + */ +public class Messages { + + private static final String sResource = + "org.apache.harmony.sql.internal.nls.messages"; //$NON-NLS-1$ + + /** + * Retrieves a message which has no arguments. + * + * @param msg + * String the key to look up. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg) { + return MsgHelp.getString(sResource, msg); + } + + /** + * Retrieves a message which takes 1 argument. + * + * @param msg + * String the key to look up. + * @param arg + * Object the object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg) { + return getString(msg, new Object[] { arg }); + } + + /** + * Retrieves a message which takes 1 integer argument. + * + * @param msg + * String the key to look up. + * @param arg + * int the integer to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, int arg) { + return getString(msg, new Object[] { Integer.toString(arg) }); + } + + /** + * Retrieves a message which takes 1 character argument. + * + * @param msg + * String the key to look up. + * @param arg + * char the character to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, char arg) { + return getString(msg, new Object[] { String.valueOf(arg) }); + } + + /** + * Retrieves a message which takes 2 arguments. + * + * @param msg + * String the key to look up. + * @param arg1 + * Object an object to insert in the formatted output. + * @param arg2 + * Object another object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg1, Object arg2) { + return getString(msg, new Object[] { arg1, arg2 }); + } + + /** + * Retrieves a message which takes several arguments. + * + * @param msg + * String the key to look up. + * @param args + * Object[] the objects to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object[] args) { + return MsgHelp.getString(sResource, msg, args); + } +} diff --git a/sql/src/main/java/org/apache/harmony/sql/internal/nls/messages.properties b/sql/src/main/java/org/apache/harmony/sql/internal/nls/messages.properties new file mode 100644 index 0000000..3e6ff1d --- /dev/null +++ b/sql/src/main/java/org/apache/harmony/sql/internal/nls/messages.properties @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# messages for EN locale +sql.0=Value out of range +sql.1=DriverManager: calling class not authorized to deregister JDBC driver +sql.2=Timestamp format must be yyyy-mm-dd hh:mm:ss.fffffffff +sql.3=Argument cannot be null +sql.4=Bad input string format: expected '.' not {0} +sql.5=The url cannot be null +sql.6=No suitable driver +sql.8=SQLWarning chain holds value that is not a SQLWarning +sql.9=Cannot instantiate a SerialRef object with a null Ref object +sql.10=Cannot instantiate a SerialRef object that returns a null base type name +sql.11=SQLException: {0} +sql.12=Cannot serialize empty URL instance +sql.13=Cannot instantiate a SerialBlob object with a null Blob object +sql.14=Invalid starting position or length +sql.15=Invalid position in BLOB object set +sql.16=Invalid offset in byte array set +sql.17=javax.sql.rowset.serial.SerialException: Length more than what can be truncated +sql.18=Unsupported operation. SerialBlob cannot return a writable binary stream, unless instantiated with a Blob object that provides a setBinaryStream() implementation +sql.19=Cannot instantiate a SerialClob object with a null Clob object +sql.20=Invalid Clob object. Calls to getCharacterStream or getAsciiStream return null which cannot be serialized. +sql.21=Invalid position in CLOB object set +sql.22=Invalid position and substring length +sql.23=Buffer is not sufficient to hold the value +sql.24=Invalid length for truncate +sql.25=Unsupported operation. SerialClob is not instantiated with a fully implemented Clob object. diff --git a/sql/src/main/native/sqlite_jni.c b/sql/src/main/native/sqlite_jni.c new file mode 100644 index 0000000..c8a76e4 --- /dev/null +++ b/sql/src/main/native/sqlite_jni.c @@ -0,0 +1,4398 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "sqlite_jni_defs.h" + +#if HAVE_SQLITE2 +#include "sqlite.h" +#endif + +#if HAVE_SQLITE3 +#include "sqlite3.h" +#undef HAVE_SQLITE_COMPILE +#define HAVE_SQLITE_COMPILE 1 +#undef HAVE_SQLITE_PROGRESS_HANDLER +#define HAVE_SQLITE_PROGRESS_HANDLER 1 +#undef HAVE_SQLITE_TRACE +#define HAVE_SQLITE_TRACE 1 +#if !HAVE_SQLITE3_MALLOC +#define sqlite3_malloc malloc +#define sqlite3_free free +#endif +#if !HAVE_SQLITE3_BIND_PARAMETER_COUNT +#define sqlite3_bind_parameter_count(dummy) (1000) +#endif +#endif + +#if HAVE_SQLITE2 && HAVE_SQLITE3 +#define HAVE_BOTH_SQLITE 1 +#endif + +#include "sqlite_jni.h" + +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) +#define MAX_PARAMS 256 +#else +#define MAX_PARAMS 32 +#endif + +/* free memory proc */ + +typedef void (freemem)(void *); + +/* internal handle for SQLite database */ + +typedef struct { + void *sqlite; /* SQLite handle */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + int ver; /* version code */ + jobject bh; /* BusyHandler object */ + jobject cb; /* Callback object */ + jobject ai; /* Authorizer object */ + jobject tr; /* Trace object */ + jobject ph; /* ProgressHandler object */ + JNIEnv *env; /* Java environment for callbacks */ + int row1; /* true while processing first row */ + int haveutf; /* true for SQLite UTF-8 support */ + jstring enc; /* encoding or 0 */ + struct hfunc *funcs; /* SQLite user defined function handles */ +#if HAVE_SQLITE_COMPILE + struct hvm *vms; /* Compiled SQLite VMs */ +#endif +#if HAVE_SQLITE3 + sqlite3_stmt *stmt; /* For callback() */ +#endif +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + struct hbl *blobs; /* SQLite3 blob handles */ +#endif +} handle; + +/* internal handle for SQLite user defined function */ + +typedef struct hfunc { + struct hfunc *next; /* next function */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + jobject fc; /* FunctionContext object */ + jobject fi; /* Function object */ + jobject db; /* Database object */ + handle *h; /* SQLite database handle */ + void *sf; /* SQLite function handle */ + JNIEnv *env; /* Java environment for callbacks */ +} hfunc; + +#if HAVE_SQLITE_COMPILE +/* internal handle for SQLite VM (sqlite_compile()) */ + +typedef struct hvm { + struct hvm *next; /* next vm handle */ +#if HAVE_BOTH_SQLITE + int is3; /* True for SQLITE3 handle */ +#endif + void *vm; /* SQLite 2/3 VM/statement */ + char *tail; /* tail SQL string */ + int tail_len; /* only for SQLite3/prepare */ + handle *h; /* SQLite database handle */ + handle hh; /* fake SQLite database handle */ +} hvm; +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +/* internal handle for sqlite3_blob */ + +typedef struct hbl { + struct hbl *next; /* next blob handle */ + sqlite3_blob *blob; /* SQLite3 blob */ + handle *h; /* SQLite database handle */ +} hbl; +#endif + +/* ISO to/from UTF-8 translation */ + +typedef struct { + char *result; /* translated C string result */ + char *tofree; /* memory to be free'd, or 0 */ + jstring jstr; /* resulting Java string or 0 */ +} transstr; + +/* static cached weak class refs, field and method ids */ + +static jclass C_java_lang_String = 0; + +static jfieldID F_SQLite_Database_handle = 0; +static jfieldID F_SQLite_Database_error_code = 0; +static jfieldID F_SQLite_FunctionContext_handle = 0; +static jfieldID F_SQLite_Vm_handle = 0; +static jfieldID F_SQLite_Vm_error_code = 0; +static jfieldID F_SQLite_Stmt_handle = 0; +static jfieldID F_SQLite_Stmt_error_code = 0; +static jfieldID F_SQLite_Blob_handle = 0; +static jfieldID F_SQLite_Blob_size = 0; + +static jmethodID M_java_lang_String_getBytes = 0; +static jmethodID M_java_lang_String_getBytes2 = 0; +static jmethodID M_java_lang_String_initBytes = 0; +static jmethodID M_java_lang_String_initBytes2 = 0; + +static const char xdigits[] = "0123456789ABCDEF"; + +static void +seterr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Database_error_code, v.i); +} + +#if HAVE_SQLITE_COMPILE +static void +setvmerr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Vm_error_code, v.i); +} + +#if HAVE_SQLITE3 +static void +setstmterr(JNIEnv *env, jobject obj, int err) +{ + jvalue v; + + v.j = 0; + v.i = (jint) err; + (*env)->SetIntField(env, obj, F_SQLite_Stmt_error_code, v.i); +} + +static int +jstrlen(const jchar *jstr) +{ + int len = 0; + + if (jstr) { + while (*jstr++) { + len++; + } + } + return len; +} +#endif +#endif + +static void * +gethandle(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Database_handle); + return (void *) v.l; +} + +#if HAVE_SQLITE_COMPILE +static void * +gethvm(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Vm_handle); + return (void *) v.l; +} + +#if HAVE_SQLITE3 +static void * +gethstmt(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Stmt_handle); + return (void *) v.l; +} +#endif +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void * +gethbl(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_Blob_handle); + return (void *) v.l; +} +#endif + +static void +delglobrefp(JNIEnv *env, jobject *obj) +{ + if (*obj) { + (*env)->DeleteGlobalRef(env, *obj); + *obj = 0; + } +} + +static jobject +globrefpop(JNIEnv *env, jobject *obj) +{ + jobject ret = 0; + + if (*obj) { + ret = *obj; + *obj = 0; + } + return ret; +} + +static void +globrefset(JNIEnv *env, jobject obj, jobject *ref) +{ + if (ref) { + if (obj) { + *ref = (*env)->NewGlobalRef(env, obj); + } else { + *ref = 0; + } + } +} + +static void +freep(char **strp) +{ + if (strp && *strp) { + free(*strp); + *strp = 0; + } +} + +static void +throwex(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "SQLite/Exception"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} + +static void +throwoom(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} + +static void +throwclosed(JNIEnv *env) +{ + throwex(env, "database already closed"); +} + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void +throwioex(JNIEnv *env, const char *msg) +{ + jclass except = (*env)->FindClass(env, "java/io/IOException"); + + (*env)->ExceptionClear(env); + if (except) { + (*env)->ThrowNew(env, except, msg); + } +} +#endif + +static void +transfree(transstr *dest) +{ + dest->result = 0; + freep(&dest->tofree); +} + +static char * +trans2iso(JNIEnv *env, int haveutf, jstring enc, jstring src, + transstr *dest) +{ + jbyteArray bytes = 0; + jthrowable exc; + + dest->result = 0; + dest->tofree = 0; + if (haveutf) { + const char *utf = (*env)->GetStringUTFChars(env, src, 0); + + if (!utf) { + return dest->result; + } + dest->tofree = malloc(strlen(utf) + 1); + dest->result = dest->tofree; + strcpy(dest->result, utf); + (*env)->ReleaseStringUTFChars(env, src, utf); + return dest->result; + } + if (enc) { + bytes = (*env)->CallObjectMethod(env, src, + M_java_lang_String_getBytes2, enc); + } else { + bytes = (*env)->CallObjectMethod(env, src, + M_java_lang_String_getBytes); + } + exc = (*env)->ExceptionOccurred(env); + if (!exc) { + jint len = (*env)->GetArrayLength(env, bytes); + dest->tofree = malloc(len + 1); + if (!dest->tofree) { + throwoom(env, "string translation failed"); + return dest->result; + } + dest->result = dest->tofree; + (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *) dest->result); + dest->result[len] = '\0'; + } else { + (*env)->DeleteLocalRef(env, exc); + } + return dest->result; +} + +static jstring +trans2utf(JNIEnv *env, int haveutf, jstring enc, const char *src, + transstr *dest) +{ + jbyteArray bytes = 0; + int len; + + dest->result = 0; + dest->tofree = 0; + dest->jstr = 0; + if (!src) { + return dest->jstr; + } + if (haveutf) { + dest->jstr = (*env)->NewStringUTF(env, src); + return dest->jstr; + } + len = strlen(src); + bytes = (*env)->NewByteArray(env, len); + if (bytes) { + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *) src); + if (enc) { + dest->jstr = + (*env)->NewObject(env, C_java_lang_String, + M_java_lang_String_initBytes2, bytes, enc); + } else { + dest->jstr = + (*env)->NewObject(env, C_java_lang_String, + M_java_lang_String_initBytes, bytes); + } + (*env)->DeleteLocalRef(env, bytes); + return dest->jstr; + } + throwoom(env, "string translation failed"); + return dest->jstr; +} + +#if HAVE_SQLITE2 +static int +busyhandler(void *udata, const char *table, int count) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->bh) { + transstr tabstr; + jclass cls = (*env)->GetObjectClass(env, h->bh); + jmethodID mid = (*env)->GetMethodID(env, cls, "busy", + "(Ljava/lang/String;I)Z"); + + if (mid == 0) { + return ret; + } + trans2utf(env, h->haveutf, h->enc, table, &tabstr); + ret = (*env)->CallBooleanMethod(env, h->bh, mid, tabstr.jstr, + (jint) count) + != JNI_FALSE; + (*env)->DeleteLocalRef(env, tabstr.jstr); + } + return ret; +} +#endif + +#if HAVE_SQLITE3 +static int +busyhandler3(void *udata, int count) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->bh) { + jclass cls = (*env)->GetObjectClass(env, h->bh); + jmethodID mid = (*env)->GetMethodID(env, cls, "busy", + "(Ljava/lang/String;I)Z"); + + if (mid == 0) { + return ret; + } + ret = (*env)->CallBooleanMethod(env, h->bh, mid, 0, (jint) count) + != JNI_FALSE; + } + return ret; +} +#endif + +static int +progresshandler(void *udata) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + int ret = 0; + + if (env && h->ph) { + jclass cls = (*env)->GetObjectClass(env, h->ph); + jmethodID mid = (*env)->GetMethodID(env, cls, "progress", "()Z"); + + if (mid == 0) { + return ret; + } + ret = (*env)->CallBooleanMethod(env, h->ph, mid) != JNI_TRUE; + } + return ret; +} + +static int +callback(void *udata, int ncol, char **data, char **cols) +{ + handle *h = (handle *) udata; + JNIEnv *env = h->env; + + if (env && h->cb) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->cb); + jmethodID mid; + jobjectArray arr = 0; + jint i; + + if (h->row1) { + mid = (*env)->GetMethodID(env, cls, "columns", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i]) { + transstr col; + + trans2utf(env, h->haveutf, h->enc, cols[i], &col); + (*env)->SetObjectArrayElement(env, arr, i, col.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, col.jstr); + } + } + h->row1 = 0; + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } +#if HAVE_BOTH_SQLITE + if (h->is3) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid && h->stmt) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + const char *ctype = + sqlite3_column_decltype(h->stmt, i); + + if (!ctype) { + switch (sqlite3_column_type(h->stmt, i)) { + case SQLITE_INTEGER: ctype = "integer"; break; + case SQLITE_FLOAT: ctype = "double"; break; + default: +#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT) + case SQLITE_TEXT: +#else +#ifdef SQLITE3_TEXT + case SQLITE3_TEXT: +#endif +#endif + ctype = "text"; break; + case SQLITE_BLOB: ctype = "blob"; break; + case SQLITE_NULL: ctype = "null"; break; + } + } + if (ctype) { + transstr ty; + + trans2utf(env, 1, 0, ctype, &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } else { + if (h->ver >= 0x020506 && cols[ncol]) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i + ncol]) { + transstr ty; + + trans2utf(env, h->haveutf, h->enc, + cols[i + ncol], &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } + } +#else +#if HAVE_SQLITE2 + if (h->ver >= 0x020506 && cols[ncol]) { + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + if (cols[i + ncol]) { + transstr ty; + + trans2utf(env, h->haveutf, h->enc, + cols[i + ncol], &ty); + (*env)->SetObjectArrayElement(env, arr, i, + ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } + } +#endif +#if HAVE_SQLITE3 + mid = (*env)->GetMethodID(env, cls, "types", + "([Ljava/lang/String;)V"); + + if (mid && h->stmt) { + arr = (*env)->NewObjectArray(env, ncol, + C_java_lang_String, 0); + for (i = 0; i < ncol; i++) { + const char *ctype = sqlite3_column_decltype(h->stmt, i); + + if (!ctype) { + switch (sqlite3_column_type(h->stmt, i)) { + case SQLITE_INTEGER: ctype = "integer"; break; + case SQLITE_FLOAT: ctype = "double"; break; + default: +#if defined(SQLITE_TEXT) && defined(SQLITE3_TEXT) && (SQLITE_TEXT != SQLITE3_TEXT) + case SQLITE_TEXT: +#else +#ifdef SQLITE3_TEXT + case SQLITE3_TEXT: +#endif +#endif + ctype = "text"; break; + case SQLITE_BLOB: ctype = "blob"; break; + case SQLITE_NULL: ctype = "null"; break; + } + } + if (ctype) { + transstr ty; + + trans2utf(env, 1, 0, ctype, &ty); + (*env)->SetObjectArrayElement(env, arr, i, ty.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, ty.jstr); + } + } + (*env)->CallVoidMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, arr); + } +#endif +#endif + } + mid = (*env)->GetMethodID(env, cls, "newrow", + "([Ljava/lang/String;)Z"); + if (mid) { + jboolean rc; + + if (data) { + arr = (*env)->NewObjectArray(env, ncol, C_java_lang_String, 0); + } else { + arr = 0; + } + for (i = 0; arr && i < ncol; i++) { + if (data[i]) { + transstr dats; + + trans2utf(env, h->haveutf, h->enc, data[i], &dats); + (*env)->SetObjectArrayElement(env, arr, i, dats.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + (*env)->DeleteLocalRef(env, dats.jstr); + } + } + rc = (*env)->CallBooleanMethod(env, h->cb, mid, arr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return 1; + } + if (arr) { + (*env)->DeleteLocalRef(env, arr); + } + (*env)->DeleteLocalRef(env, cls); + return rc != JNI_FALSE; + } + } + return 0; +} + +static void +doclose(JNIEnv *env, jobject obj, int final) +{ + handle *h = gethandle(env, obj); + + if (h) { + hfunc *f; +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl; +#endif +#if HAVE_SQLITE_COMPILE + hvm *v; + + while ((v = h->vms)) { + h->vms = v->next; + v->next = 0; + v->h = 0; + if (v->vm) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + } +#endif + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + } else { + sqlite_close((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + h->sqlite = 0; + } + while ((f = h->funcs)) { + h->funcs = f->next; + f->h = 0; + f->sf = 0; + f->env = 0; + if (f->fc) { + (*env)->SetLongField(env, f->fc, + F_SQLite_FunctionContext_handle, 0); + } + delglobrefp(env, &f->db); + delglobrefp(env, &f->fi); + delglobrefp(env, &f->fc); + free(f); + } +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + while ((bl = h->blobs)) { + h->blobs = bl->next; + bl->next = 0; + bl->h = 0; + if (bl->blob) { + sqlite3_blob_close(bl->blob); + } + bl->blob = 0; + } +#endif + delglobrefp(env, &h->bh); + delglobrefp(env, &h->cb); + delglobrefp(env, &h->ai); + delglobrefp(env, &h->tr); + delglobrefp(env, &h->ph); + delglobrefp(env, &h->enc); + free(h); + (*env)->SetLongField(env, obj, F_SQLite_Database_handle, 0); + return; + } + if (!final) { + throwclosed(env); + } +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1close(JNIEnv *env, jobject obj) +{ + doclose(env, obj, 0); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1finalize(JNIEnv *env, jobject obj) +{ + doclose(env, obj, 1); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1busy_1timeout(JNIEnv *env, jobject obj, jint ms) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms); + } else { + sqlite_busy_timeout((sqlite *) h->sqlite, ms); + } +#else +#if HAVE_SQLITE2 + sqlite_busy_timeout((sqlite *) h->sqlite, ms); +#endif +#if HAVE_SQLITE3 + sqlite3_busy_timeout((sqlite3 * ) h->sqlite, ms); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_version(JNIEnv *env, jclass cls) +{ + /* CHECK THIS */ +#if HAVE_BOTH_SQLITE + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else + return (*env)->NewStringUTF(env, sqlite3_libversion()); +#endif +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_dbversion(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (*env)->NewStringUTF(env, sqlite3_libversion()); + } else { + return (*env)->NewStringUTF(env, sqlite_libversion()); + } +#else +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_libversion()); +#else + return (*env)->NewStringUTF(env, sqlite3_libversion()); +#endif +#endif + } + return (*env)->NewStringUTF(env, "unknown"); +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Database__1last_1insert_1rowid(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite); + } else { + return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + return (jlong) sqlite_last_insert_rowid((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + return (jlong) sqlite3_last_insert_rowid((sqlite3 *) h->sqlite); +#endif +#endif + } + throwclosed(env); + return (jlong) 0; +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Database__1changes(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return (jlong) sqlite3_changes((sqlite3 *) h->sqlite); + } else { + return (jlong) sqlite_changes((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + return (jlong) sqlite_changes((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + return (jlong) sqlite3_changes((sqlite3 *) h->sqlite); +#endif +#endif + } + throwclosed(env); + return (jlong) 0; +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Database__1complete(JNIEnv *env, jclass cls, jstring sql) +{ + transstr sqlstr; + jboolean result; + + if (!sql) { + return JNI_FALSE; + } +#if HAVE_BOTH_SQLITE || HAVE_SQLITE3 + /* CHECK THIS */ + trans2iso(env, 1, 0, sql, &sqlstr); + result = sqlite3_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE; +#else + trans2iso(env, strcmp(sqlite_libencoding(), "UTF-8") == 0, 0, + sql, &sqlstr); + result = sqlite_complete(sqlstr.result) ? JNI_TRUE : JNI_FALSE; +#endif + transfree(&sqlstr); + return result; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1interrupt(JNIEnv *env, jobject obj) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_interrupt((sqlite3 *) h->sqlite); + } else { + sqlite_interrupt((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_interrupt((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_interrupt((sqlite3 *) h->sqlite); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open(JNIEnv *env, jobject obj, jstring file, jint mode) +{ + handle *h = gethandle(env, obj); + jthrowable exc; + char *err = 0; + transstr filename; + int maj, min, lev; + + if (h) { + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + } else { + sqlite_close((sqlite *) h->sqlite); + } + h->is3 = 0; +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + h->sqlite = 0; + } + } else { + h = malloc(sizeof (handle)); + if (!h) { + throwoom(env, "unable to get SQLite handle"); + return; + } + h->sqlite = 0; + h->bh = h->cb = h->ai = h->tr = h->ph = 0; + /* CHECK THIS */ +#if HAVE_BOTH_SQLITE + h->is3 = 0; + h->stmt = 0; + h->haveutf = 1; +#else +#if HAVE_SQLITE2 + h->haveutf = strcmp(sqlite_libencoding(), "UTF-8") == 0; +#endif +#if HAVE_SQLITE3 + h->stmt = 0; + h->haveutf = 1; +#endif +#endif + h->enc = 0; + h->funcs = 0; + h->ver = 0; +#if HAVE_SQLITE_COMPILE + h->vms = 0; +#endif +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + h->blobs = 0; +#endif + } + h->env = 0; + if (!file) { + throwex(env, err ? err : "invalid file name"); + return; + } + trans2iso(env, h->haveutf, h->enc, file, &filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + { + FILE *f = fopen(filename.result, "rb"); + int c_0 = EOF; + + if (f) { + c_0 = fgetc(f); + fclose(f); + } + if (c_0 != '*') { + int rc = sqlite3_open(filename.result, (sqlite3 **) &h->sqlite); + + if (rc == SQLITE_OK) { + h->is3 = 1; + } else if (h->sqlite) { + sqlite3_close((sqlite3 *) h->sqlite); + h->sqlite = 0; + } + } else { + h->sqlite = (void *) sqlite_open(filename.result, + (int) mode, &err); + } + } +#else +#if HAVE_SQLITE2 + h->sqlite = (void *) sqlite_open(filename.result, (int) mode, &err); +#endif +#if HAVE_SQLITE3 + if (sqlite3_open(filename.result, (sqlite3 **) &h->sqlite) != SQLITE_OK) { + if (h->sqlite) { + sqlite3_close((sqlite3 *) h->sqlite); + h->sqlite = 0; + } + } +#endif +#endif + transfree(&filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_close((sqlite3 *) h->sqlite); + h->is3 = 0; + } else { + sqlite_close((sqlite *) h->sqlite); + } +#else +#if HAVE_SQLITE2 + sqlite_close((sqlite *) h->sqlite); +#endif +#if HAVE_SQLITE3 + sqlite3_close((sqlite3 *) h->sqlite); +#endif +#endif + } + h->sqlite = 0; + return; + } + if (h->sqlite) { + jvalue v; + + v.j = 0; + v.l = (jobject) h; + (*env)->SetLongField(env, obj, F_SQLite_Database_handle, v.j); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif +#if HAVE_BOTH_SQLITE + if (h->is3) { + sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev); + } else { + sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev); + } +#else +#if HAVE_SQLITE2 + sscanf(sqlite_libversion(), "%d.%d.%d", &maj, &min, &lev); +#endif +#if HAVE_SQLITE3 + sscanf(sqlite3_libversion(), "%d.%d.%d", &maj, &min, &lev); +#endif +#endif + h->ver = ((maj & 0xFF) << 16) | ((min & 0xFF) << 8) | (lev & 0xFF); + return; + } + throwex(env, err ? err : "unknown error in open"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open_1aux_1file(JNIEnv *env, jobject obj, jstring file) +{ + handle *h = gethandle(env, obj); +#if HAVE_SQLITE_OPEN_AUX_FILE + jboolean b; + jthrowable exc; + char *err = 0; + transstr filename; + int ret; +#endif + + if (h && h->sqlite) { +#if HAVE_SQLITE_OPEN_AUX_FILE +#if HAVE_BOTH_SQLITE + if (h->is3) { + throwex(env, "unsupported"); + } +#endif + trans2iso(env, h->haveutf, h->enc, file, &filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite_open_aux_file((sqlite *) h->sqlite, + filename.result, &err); + transfree(&filename); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err) { + sqlite_freemem(err); + } + return; + } + if (ret != SQLITE_OK) { + throwex(env, err ? err : sqlite_error_string(ret)); + } + if (err) { + sqlite_freemem(err); + } +#else + throwex(env, "unsupported"); +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1busy_1handler(JNIEnv *env, jobject obj, jobject bh) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->bh); + globrefset(env, bh, &h->bh); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h); + } else { + sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h); + } +#else +#if HAVE_SQLITE2 + sqlite_busy_handler((sqlite *) h->sqlite, busyhandler, h); +#endif +#if HAVE_SQLITE3 + sqlite3_busy_handler((sqlite3 *) h->sqlite, busyhandler3, h); +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2 + (JNIEnv *env, jobject obj, jstring sql, jobject cb) +{ + handle *h = gethandle(env, obj); + freemem *freeproc; + + if (!sql) { + throwex(env, "invalid SQL statement"); + return; + } + if (h) { + if (h->sqlite) { + jthrowable exc; + int rc; + char *err = 0; + transstr sqlstr; + jobject oldcb = globrefpop(env, &h->cb); + + globrefset(env, cb, &h->cb); + h->env = env; + h->row1 = 1; + trans2iso(env, h->haveutf, h->enc, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + if (h->is3) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite3_free; + } else { + rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite_freemem; + } +#else +#if HAVE_SQLITE2 + rc = sqlite_exec((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite_freemem; +#endif +#if HAVE_SQLITE3 + rc = sqlite3_exec((sqlite3 *) h->sqlite, sqlstr.result, + callback, h, &err); + freeproc = (freemem *) sqlite3_free; +#endif +#endif + transfree(&sqlstr); + exc = (*env)->ExceptionOccurred(env); + delglobrefp(env, &h->cb); + h->cb = oldcb; + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err) { + freeproc(err); + } + return; + } + if (rc != SQLITE_OK) { + char msg[128]; + + seterr(env, obj, rc); + if (!err) { + sprintf(msg, "error %d in sqlite*_exec", rc); + } + throwex(env, err ? err : msg); + } + if (err) { + freeproc(err); + } + return; + } + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2 + (JNIEnv *env, jobject obj, jstring sql, jobject cb, jobjectArray args) +{ + handle *h = gethandle(env, obj); + freemem *freeproc = 0; + + if (!sql) { + throwex(env, "invalid SQL statement"); + return; + } + if (h) { + if (h->sqlite) { + jboolean b; + jthrowable exc; + int rc = SQLITE_ERROR, nargs, i; + char *err = 0, *p; + const char *str = (*env)->GetStringUTFChars(env, sql, &b); + transstr sqlstr; + struct args { + char *arg; + jobject obj; + transstr trans; + } *argv = 0; + char **cargv = 0; + jobject oldcb = globrefpop(env, &h->cb); + + globrefset(env, cb, &h->cb); + p = (char *) str; + nargs = 0; + while (*p) { + if (*p == '%') { + ++p; + if (*p == 'q' || *p == 's') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "too much SQL parameters"); + return; + } + } else if (h->ver >= 0x020500 && *p == 'Q') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "too much SQL parameters"); + return; + } + } else if (*p != '%') { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwex(env, "bad % specification in query"); + return; + } + } + ++p; + } + cargv = malloc((sizeof (*argv) + sizeof (char *)) + * MAX_PARAMS); + if (!cargv) { + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + throwoom(env, "unable to allocate arg vector"); + return; + } + argv = (struct args *) (cargv + MAX_PARAMS); + for (i = 0; i < MAX_PARAMS; i++) { + cargv[i] = 0; + argv[i].arg = 0; + argv[i].obj = 0; + argv[i].trans.result = argv[i].trans.tofree = 0; + } + exc = 0; + for (i = 0; i < nargs; i++) { + jobject so = (*env)->GetObjectArrayElement(env, args, i); + + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + break; + } + if (so) { + argv[i].obj = so; + argv[i].arg = cargv[i] = + trans2iso(env, h->haveutf, h->enc, argv[i].obj, + &argv[i].trans); + } + } + if (exc) { + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + (*env)->ReleaseStringUTFChars(env, sql, str); + delglobrefp(env, &h->cb); + h->cb = oldcb; + return; + } + h->env = env; + h->row1 = 1; + trans2iso(env, h->haveutf, h->enc, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (!exc) { +#if HAVE_BOTH_SQLITE + if (h->is3) { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + + if (s) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback, + h, &err); + sqlite3_free(s); + } else { + rc = SQLITE_NOMEM; + } + freeproc = (freemem *) sqlite3_free; + } else { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + rc = sqlite_exec_vprintf((sqlite *) h->sqlite, + sqlstr.result, callback, h, &err, + (char *) cargv); +#else + rc = sqlite_exec_printf((sqlite *) h->sqlite, + sqlstr.result, callback, + h, &err, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + freeproc = (freemem *) sqlite_freemem; + } +#else +#if HAVE_SQLITE2 +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + rc = sqlite_exec_vprintf((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err, (char *) cargv); +#else + rc = sqlite_exec_printf((sqlite *) h->sqlite, sqlstr.result, + callback, h, &err, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + freeproc = (freemem *) sqlite_freemem; +#endif +#if HAVE_SQLITE3 +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + + if (s) { + rc = sqlite3_exec((sqlite3 *) h->sqlite, s, callback, + h, &err); + sqlite3_free(s); + } else { + rc = SQLITE_NOMEM; + } + freeproc = (freemem *) sqlite3_free; +#endif +#endif + exc = (*env)->ExceptionOccurred(env); + } + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + freep((char **) &cargv); + delglobrefp(env, &h->cb); + h->cb = oldcb; + if (exc) { + (*env)->DeleteLocalRef(env, exc); + if (err && freeproc) { + freeproc(err); + } + return; + } + if (rc != SQLITE_OK) { + char msg[128]; + + seterr(env, obj, rc); + if (!err) { + sprintf(msg, "error %d in sqlite*_exec", rc); + } + throwex(env, err ? err : msg); + } + if (err && freeproc) { + freeproc(err); + } + return; + } + } + throwclosed(env); +} + +static hfunc * +getfunc(JNIEnv *env, jobject obj) +{ + jvalue v; + + v.j = (*env)->GetLongField(env, obj, F_SQLite_FunctionContext_handle); + return (hfunc *) v.l; +} + +#if HAVE_SQLITE2 +static void +call_common(sqlite_func *sf, int isstep, int nargs, const char **args) +{ + hfunc *f = (hfunc *) sqlite_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = + (*env)->GetMethodID(env, cls, + isstep ? "step" : "function", + "(LSQLite/FunctionContext;[Ljava/lang/String;)V"); + jobjectArray arr; + int i; + + if (mid == 0) { + return; + } + arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0); + for (i = 0; i < nargs; i++) { + if (args[i]) { + transstr arg; + jthrowable exc; + + trans2utf(env, f->h->haveutf, f->h->enc, args[i], &arg); + (*env)->SetObjectArrayElement(env, arr, i, arg.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + (*env)->DeleteLocalRef(env, arg.jstr); + } + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr); + (*env)->DeleteLocalRef(env, arr); + (*env)->DeleteLocalRef(env, cls); + } +} + +static void +call_func(sqlite_func *sf, int nargs, const char **args) +{ + call_common(sf, 0, nargs, args); +} + +static void +call_step(sqlite_func *sf, int nargs, const char **args) +{ + call_common(sf, 1, nargs, args); +} + +static void +call_final(sqlite_func *sf) +{ + hfunc *f = (hfunc *) sqlite_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = (*env)->GetMethodID(env, cls, "last_step", + "(LSQLite/FunctionContext;)V"); + if (mid == 0) { + return; + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc); + (*env)->DeleteLocalRef(env, cls); + } +} +#endif + +#if HAVE_SQLITE3 +static void +call3_common(sqlite3_context *sf, int isstep, int nargs, sqlite3_value **args) +{ + hfunc *f = (hfunc *) sqlite3_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = + (*env)->GetMethodID(env, cls, + isstep ? "step" : "function", + "(LSQLite/FunctionContext;[Ljava/lang/String;)V"); + jobjectArray arr; + int i; + + if (mid == 0) { + return; + } + arr = (*env)->NewObjectArray(env, nargs, C_java_lang_String, 0); + for (i = 0; i < nargs; i++) { + if (args[i]) { + transstr arg; + jthrowable exc; + + trans2utf(env, 1, 0, (char *) sqlite3_value_text(args[i]), + &arg); + (*env)->SetObjectArrayElement(env, arr, i, arg.jstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + (*env)->DeleteLocalRef(env, arg.jstr); + } + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc, arr); + (*env)->DeleteLocalRef(env, arr); + (*env)->DeleteLocalRef(env, cls); + } +} + +static void +call3_func(sqlite3_context *sf, int nargs, sqlite3_value **args) +{ + call3_common(sf, 0, nargs, args); +} + +static void +call3_step(sqlite3_context *sf, int nargs, sqlite3_value **args) +{ + call3_common(sf, 1, nargs, args); +} + +static void +call3_final(sqlite3_context *sf) +{ + hfunc *f = (hfunc *) sqlite3_user_data(sf); + + if (f && f->env && f->fi) { + JNIEnv *env = f->env; + jclass cls = (*env)->GetObjectClass(env, f->fi); + jmethodID mid = (*env)->GetMethodID(env, cls, "last_step", + "(LSQLite/FunctionContext;)V"); + if (mid == 0) { + return; + } + f->sf = sf; + (*env)->CallVoidMethod(env, f->fi, mid, f->fc); + (*env)->DeleteLocalRef(env, cls); + } +} +#endif + +static void +mkfunc_common(JNIEnv *env, int isagg, jobject obj, jstring name, + jint nargs, jobject fi) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + jclass cls = (*env)->FindClass(env, "SQLite/FunctionContext"); + jobject fc; + hfunc *f; + int ret; + transstr namestr; + jvalue v; + jthrowable exc; + + fc = (*env)->AllocObject(env, cls); + if (!fi) { + throwex(env, "null SQLite.Function not allowed"); + return; + } + f = malloc(sizeof (hfunc)); + if (!f) { + throwoom(env, "unable to get SQLite.FunctionContext handle"); + return; + } + globrefset(env, fc, &f->fc); + globrefset(env, fi, &f->fi); + globrefset(env, obj, &f->db); + f->h = h; + f->next = h->funcs; + h->funcs = f; + f->sf = 0; + f->env = env; + v.j = 0; + v.l = (jobject) f; + (*env)->SetLongField(env, f->fc, F_SQLite_FunctionContext_handle, v.j); + trans2iso(env, h->haveutf, h->enc, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } +#if HAVE_BOTH_SQLITE + f->is3 = h->is3; + if (h->is3) { + ret = sqlite3_create_function((sqlite3 *) h->sqlite, + namestr.result, + (int) nargs, + SQLITE_UTF8, f, + isagg ? NULL : call3_func, + isagg ? call3_step : NULL, + isagg ? call3_final : NULL); + + } else { + if (isagg) { + ret = sqlite_create_aggregate((sqlite *) h->sqlite, + namestr.result, + (int) nargs, + call_step, call_final, f); + } else { + ret = sqlite_create_function((sqlite *) h->sqlite, + namestr.result, + (int) nargs, + call_func, f); + } + } +#else +#if HAVE_SQLITE2 + if (isagg) { + ret = sqlite_create_aggregate((sqlite *) h->sqlite, namestr.result, + (int) nargs, + call_step, call_final, f); + } else { + ret = sqlite_create_function((sqlite *) h->sqlite, namestr.result, + (int) nargs, + call_func, f); + } +#endif +#if HAVE_SQLITE3 + ret = sqlite3_create_function((sqlite3 *) h->sqlite, + namestr.result, + (int) nargs, + SQLITE_UTF8, f, + isagg ? NULL : call3_func, + isagg ? call3_step : NULL, + isagg ? call3_final : NULL); +#endif +#endif + transfree(&namestr); + if (ret != SQLITE_OK) { + throwex(env, "error creating function/aggregate"); + } + return; + } + throwclosed(env); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1create_1aggregate(JNIEnv *env, jobject obj, + jstring name, jint nargs, jobject fi) +{ + mkfunc_common(env, 1, obj, name, nargs, fi); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1create_1function(JNIEnv *env, jobject obj, + jstring name, jint nargs, jobject fi) +{ + mkfunc_common(env, 0, obj, name, nargs, fi); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1function_1type(JNIEnv *env, jobject obj, + jstring name, jint type) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (h->is3) { + return; + } +#endif +#if HAVE_SQLITE2 +#if HAVE_SQLITE_FUNCTION_TYPE + { + int ret; + transstr namestr; + jthrowable exc; + + trans2iso(env, h->haveutf, h->enc, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite_function_type(h->sqlite, namestr.result, (int) type); + transfree(&namestr); + if (ret != SQLITE_OK) { + throwex(env, sqlite_error_string(ret)); + } + } +#endif +#endif + return; + } + throwclosed(env); +} + +JNIEXPORT jint JNICALL +Java_SQLite_FunctionContext_count(JNIEnv *env, jobject obj) +{ + hfunc *f = getfunc(env, obj); + jint r = 0; + + if (f && f->sf) { +#if HAVE_SQLITE_BOTH + if (f->is3) { + r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf); + } else { + r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf); + } +#else +#if HAVE_SQLITE2 + r = (jint) sqlite_aggregate_count((sqlite_func *) f->sf); +#endif +#if HAVE_SQLITE3 + r = (jint) sqlite3_aggregate_count((sqlite3_context *) f->sf); +#endif +#endif + } + return r; +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1error(JNIEnv *env, jobject obj, jstring err) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + transstr errstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_error((sqlite_func *) f->sf, + errstr.result, -1); + transfree(&errstr); + } else if (err) { + jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, err, 0); + + sqlite3_result_error16((sqlite3_context *) f->sf, str, len); + (*env)->ReleaseStringChars(env, err, str); + } else { + sqlite3_result_error((sqlite3_context *) f->sf, + "null error text", -1); + } +#else +#if HAVE_SQLITE2 + transstr errstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, err, &errstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_error((sqlite_func *) f->sf, errstr.result, -1); + transfree(&errstr); +#endif +#if HAVE_SQLITE3 + if (err) { + jsize len = (*env)->GetStringLength(env, err) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, err, 0); + + sqlite3_result_error16((sqlite3_context *) f->sf, str, len); + (*env)->ReleaseStringChars(env, err, str); + } else { + sqlite3_result_error((sqlite3_context *) f->sf, + "null error text", -1); + } +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__D(JNIEnv *env, jobject obj, jdouble d) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (f->is3) { + sqlite3_result_double((sqlite3_context *) f->sf, (double) d); + } else { + sqlite_set_result_double((sqlite_func *) f->sf, (double) d); + } +#else +#if HAVE_SQLITE2 + sqlite_set_result_double((sqlite_func *) f->sf, (double) d); +#endif +#if HAVE_SQLITE3 + sqlite3_result_double((sqlite3_context *) f->sf, (double) d); +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__I(JNIEnv *env, jobject obj, jint i) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (f->is3) { + sqlite3_result_int((sqlite3_context *) f->sf, (int) i); + } else { + sqlite_set_result_int((sqlite_func *) f->sf, (int) i); + } +#else +#if HAVE_SQLITE2 + sqlite_set_result_int((sqlite_func *) f->sf, (int) i); +#endif +#if HAVE_SQLITE3 + sqlite3_result_int((sqlite3_context *) f->sf, (int) i); +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2(JNIEnv *env, + jobject obj, + jstring ret) +{ + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + transstr retstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_string((sqlite_func *) f->sf, + retstr.result, -1); + transfree(&retstr); + } else if (ret) { + jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, ret, 0); + + sqlite3_result_text16((sqlite3_context *) f->sf, str, len, + SQLITE_TRANSIENT); + (*env)->ReleaseStringChars(env, ret, str); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } +#else +#if HAVE_SQLITE2 + transstr retstr; + jthrowable exc; + + trans2iso(env, f->h->haveutf, f->h->enc, ret, &retstr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + sqlite_set_result_string((sqlite_func *) f->sf, retstr.result, -1); + transfree(&retstr); +#endif +#if HAVE_SQLITE3 + if (ret) { + jsize len = (*env)->GetStringLength(env, ret) * sizeof (jchar); + const jchar *str = (*env)->GetStringChars(env, ret, 0); + + sqlite3_result_text16((sqlite3_context *) f->sf, str, len, + SQLITE_TRANSIENT); + (*env)->ReleaseStringChars(env, ret, str); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } +#endif +#endif + } +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result___3B(JNIEnv *env, jobject obj, + jbyteArray b) +{ +#if HAVE_SQLITE3 + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + /* silently ignored */ + return; + } +#endif + if (b) { + jsize len; + jbyte *data; + + len = (*env)->GetArrayLength(env, b); + data = (*env)->GetByteArrayElements(env, b, 0); + sqlite3_result_blob((sqlite3_context *) f->sf, + data, len, SQLITE_TRANSIENT); + (*env)->ReleaseByteArrayElements(env, b, data, 0); + } else { + sqlite3_result_null((sqlite3_context *) f->sf); + } + } +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_set_1result_1zeroblob(JNIEnv *env, jobject obj, + jint n) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_RESULT_ZEROBLOB + hfunc *f = getfunc(env, obj); + + if (f && f->sf) { +#if HAVE_BOTH_SQLITE + if (!f->is3) { + /* silently ignored */ + return; + } +#endif + sqlite3_result_zeroblob((sqlite3_context *) f->sf, n); + } +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database_error_1string(JNIEnv *env, jclass c, jint err) +{ +#if HAVE_SQLITE2 + return (*env)->NewStringUTF(env, sqlite_error_string((int) err)); +#else + return (*env)->NewStringUTF(env, "unkown error"); +#endif +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Database__1errmsg(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { +#if HAVE_BOTH_SQLITE + if (!h->is3) { + return 0; + } +#endif + return (*env)->NewStringUTF(env, + sqlite3_errmsg((sqlite3 *) h->sqlite)); + } +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1set_1encoding(JNIEnv *env, jobject obj, jstring enc) +{ + handle *h = gethandle(env, obj); + + if (h && !h->haveutf) { +#if HAVE_BOTH_SQLITE + if (!h->is3) { + delglobrefp(env, &h->enc); + h->enc = enc; + globrefset(env, enc, &h->enc); + } +#else +#if HAVE_SQLITE2 + delglobrefp(env, &h->enc); + h->enc = enc; + globrefset(env, enc, &h->enc); +#endif +#endif + } +} + +#if HAVE_SQLITE_SET_AUTHORIZER +static int +doauth(void *arg, int what, const char *arg1, const char *arg2, + const char *arg3, const char *arg4) +{ + handle *h = (handle *) arg; + JNIEnv *env = h->env; + + if (env && h->ai) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->ai); + jmethodID mid; + jint i = what; + + mid = (*env)->GetMethodID(env, cls, "authorize", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I"); + if (mid) { + jstring s1 = 0, s2 = 0, s3 = 0, s4 = 0; + transstr tr; + + if (arg1) { + trans2utf(env, h->haveutf, h->enc, arg1, &tr); + s1 = tr.jstr; + } + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + if (arg2) { + trans2utf(env, h->haveutf, h->enc, arg2, &tr); + s2 = tr.jstr; + } + if (arg3) { + trans2utf(env, h->haveutf, h->enc, arg3, &tr); + s3 = tr.jstr; + } + if (arg4) { + trans2utf(env, h->haveutf, h->enc, arg4, &tr); + s4 = tr.jstr; + } + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + i = (*env)->CallIntMethod(env, h->ai, mid, i, s1, s2, s3, s4); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return SQLITE_DENY; + } + (*env)->DeleteLocalRef(env, s4); + (*env)->DeleteLocalRef(env, s3); + (*env)->DeleteLocalRef(env, s2); + (*env)->DeleteLocalRef(env, s1); + if (i != SQLITE_OK && i != SQLITE_IGNORE) { + i = SQLITE_DENY; + } + return (int) i; + } + } + return SQLITE_DENY; +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Database__1set_1authorizer(JNIEnv *env, jobject obj, jobject auth) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->ai); + globrefset(env, auth, &h->ai); +#if HAVE_SQLITE_SET_AUTHORIZER + h->env = env; +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_set_authorizer((sqlite3 *) h->sqlite, + h->ai ? doauth : 0, h); + } else { + sqlite_set_authorizer((sqlite *) h->sqlite, + h->ai ? doauth : 0, h); + } +#else +#if HAVE_SQLITE2 + sqlite_set_authorizer((sqlite *) h->sqlite, h->ai ? doauth : 0, h); +#endif +#if HAVE_SQLITE3 + sqlite3_set_authorizer((sqlite3 *) h->sqlite, h->ai ? doauth : 0, h); +#endif +#endif +#endif + return; + } + throwclosed(env); +} + +#if HAVE_SQLITE_TRACE +static void +dotrace(void *arg, const char *msg) +{ + handle *h = (handle *) arg; + JNIEnv *env = h->env; + + if (env && h->tr && msg) { + jthrowable exc; + jclass cls = (*env)->GetObjectClass(env, h->tr); + jmethodID mid; + + mid = (*env)->GetMethodID(env, cls, "trace", "(Ljava/lang/String;)V"); + if (mid) { + transstr tr; + + trans2utf(env, h->haveutf, h->enc, msg, &tr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + (*env)->ExceptionClear(env); + return; + } + (*env)->CallVoidMethod(env, h->tr, mid, tr.jstr); + (*env)->ExceptionClear(env); + (*env)->DeleteLocalRef(env, tr.jstr); + return; + } + } + return; +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Database__1trace(JNIEnv *env, jobject obj, jobject tr) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + delglobrefp(env, &h->tr); + globrefset(env, tr, &h->tr); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h); + } else { +#if HAVE_SQLITE_TRACE + sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h); +#endif + } +#else +#if HAVE_SQLITE2 +#if HAVE_SQLITE_TRACE + sqlite_trace((sqlite *) h->sqlite, h->tr ? dotrace : 0, h); +#endif +#endif +#if HAVE_SQLITE3 + sqlite3_trace((sqlite3 *) h->sqlite, h->tr ? dotrace : 0, h); +#endif +#endif + return; + } + throwclosed(env); +} + +#if HAVE_SQLITE_COMPILE +static void +dovmfinal(JNIEnv *env, jobject obj, int final) +{ + hvm *v = gethvm(env, obj); + + if (v) { + if (v->h) { + handle *h = v->h; + hvm *vv, **vvp; + + vvp = &h->vms; + vv = *vvp; + while (vv) { + if (vv == v) { + *vvp = vv->next; + break; + } + vvp = &vv->next; + vv = *vvp; + } + } + if (v->vm) { +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + free(v); + (*env)->SetLongField(env, obj, F_SQLite_Vm_handle, 0); + return; + } + if (!final) { + throwex(env, "vm already closed"); + } +} +#endif + +#if HAVE_SQLITE3 +static void +dostmtfinal(JNIEnv *env, jobject obj) +{ + hvm *v = gethstmt(env, obj); + + if (v) { + if (v->h) { + handle *h = v->h; + hvm *vv, **vvp; + + vvp = &h->vms; + vv = *vvp; + while (vv) { + if (vv == v) { + *vvp = vv->next; + break; + } + vvp = &vv->next; + vv = *vvp; + } + } + if (v->vm) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } + v->vm = 0; + free(v); + (*env)->SetLongField(env, obj, F_SQLite_Stmt_handle, 0); + } +} +#endif + +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO +static void +doblobfinal(JNIEnv *env, jobject obj) +{ + hbl *bl = gethbl(env, obj); + + if (bl) { + if (bl->h) { + handle *h = bl->h; + hbl *blc, **blp; + + blp = &h->blobs; + blc = *blp; + while (blc) { + if (blc == bl) { + *blp = blc->next; + break; + } + blp = &blc->next; + blc = *blp; + } + } + if (bl->blob) { + sqlite3_blob_close(bl->blob); + } + bl->blob = 0; + free(bl); + (*env)->SetLongField(env, obj, F_SQLite_Blob_handle, 0); + (*env)->SetIntField(env, obj, F_SQLite_Blob_size, 0); + } +} +#endif + +JNIEXPORT void JNICALL +Java_SQLite_Vm_stop(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + dovmfinal(env, obj, 0); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Vm_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + dovmfinal(env, obj, 1); +#endif +} + +#if HAVE_SQLITE_COMPILE +#if HAVE_SQLITE3 +static void +free_tab(void *mem) +{ + char **p = (char **) mem; + int i, n; + + if (!p) { + return; + } + p -= 1; + mem = (void *) p; + n = ((int *) p)[0]; + p += n * 2 + 2 + 1; + for (i = 0; i < n; i++) { + if (p[i]) { + free(p[i]); + } + } + free(mem); +} +#endif +#endif + +JNIEXPORT jboolean JNICALL +Java_SQLite_Vm_step(JNIEnv *env, jobject obj, jobject cb) +{ +#if HAVE_SQLITE_COMPILE + hvm *v = gethvm(env, obj); + + if (v && v->vm && v->h) { + jthrowable exc; + int ret, ncol = 0; +#if HAVE_SQLITE3 + freemem *freeproc = 0; + const char **blob = 0; +#endif + const char **data = 0, **cols = 0; + + v->h->env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + if (ncol > 0) { + data = calloc(ncol * 3 + 3 + 1, sizeof (char *)); + if (data) { + data[0] = (const char *) ncol; + ++data; + cols = data + ncol + 1; + blob = cols + ncol + 1; + freeproc = free_tab; + } else { + ret = SQLITE_NOMEM; + } + } + if (ret != SQLITE_NOMEM) { + int i; + + for (i = 0; i < ncol; i++) { + cols[i] = + sqlite3_column_name((sqlite3_stmt *) v->vm, i); + if (sqlite3_column_type((sqlite3_stmt *) v->vm, i) + == SQLITE_BLOB) { + unsigned char *src = (unsigned char *) + sqlite3_column_blob((sqlite3_stmt *) v->vm, i); + int n = + sqlite3_column_bytes((sqlite3_stmt *) v->vm, + i); + + if (src) { + data[i] = malloc(n * 2 + 4); + if (data[i]) { + int k; + char *p = (char *) data[i]; + + blob[i] = data[i]; + *p++ = 'X'; + *p++ = '\''; + for (k = 0; k < n; k++) { + *p++ = xdigits[src[k] >> 4]; + *p++ = xdigits[src[k] & 0x0F]; + } + *p++ = '\''; + *p++ = '\0'; + } + } + } else { + data[i] = (const char *) + sqlite3_column_text((sqlite3_stmt *) v->vm, i); + } + } + } + } + } else { + ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols); + } +#else +#if HAVE_SQLITE2 + ret = sqlite_step((sqlite_vm *) v->vm, &ncol, &data, &cols); +#endif +#if HAVE_SQLITE3 + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + if (ncol > 0) { + data = calloc(ncol * 3 + 3 + 1, sizeof (char *)); + if (data) { + data[0] = (const char *) ncol; + ++data; + cols = data + ncol + 1; + blob = cols + ncol + 1; + freeproc = free_tab; + } else { + ret = SQLITE_NOMEM; + } + } + if (ret != SQLITE_NOMEM) { + int i; + + for (i = 0; i < ncol; i++) { + cols[i] = sqlite3_column_name((sqlite3_stmt *) v->vm, i); + if (sqlite3_column_type((sqlite3_stmt *) v->vm, i) + == SQLITE_BLOB) { + unsigned char *src = (unsigned char *) + sqlite3_column_blob((sqlite3_stmt *) v->vm, i); + int n = + sqlite3_column_bytes((sqlite3_stmt *) v->vm, i); + + if (src) { + data[i] = malloc(n * 2 + 4); + if (data[i]) { + int k; + char *p = (char *) data[i]; + + blob[i] = data[i]; + *p++ = 'X'; + *p++ = '\''; + for (k = 0; k < n; k++) { + *p++ = xdigits[src[k] >> 4]; + *p++ = xdigits[src[k] & 0x0F]; + } + *p++ = '\''; + *p++ = '\0'; + } + } + } else { + data[i] = (char *) + sqlite3_column_text((sqlite3_stmt *) v->vm, i); + } + } + } + } +#endif +#endif + if (ret == SQLITE_ROW) { + v->hh.cb = cb; + v->hh.env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { + v->hh.stmt = (sqlite3_stmt *) v->vm; + } +#else +#if HAVE_SQLITE3 + v->hh.stmt = (sqlite3_stmt *) v->vm; +#endif +#endif + callback((void *) &v->hh, ncol, (char **) data, (char **) cols); +#if HAVE_SQLITE3 + if (data && freeproc) { + freeproc((void *) data); + } +#endif + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + goto dofin; + } + return JNI_TRUE; + } else if (ret == SQLITE_DONE) { +dofin: +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + return JNI_FALSE; + } +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + setvmerr(env, obj, ret); + v->vm = 0; + throwex(env, "error in step"); + return JNI_FALSE; + } + throwex(env, "vm already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Vm_compile(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE_COMPILE + hvm *v = gethvm(env, obj); + void *svm = 0; + char *err = 0; + const char *tail; + int ret; + + if (v && v->vm) { +#if HAVE_BOTH_SQLITE + if (v->is3) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + } else { + sqlite_finalize((sqlite_vm *) v->vm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) v->vm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) v->vm); +#endif +#endif + v->vm = 0; + } + if (v && v->h && v->h->sqlite) { + if (!v->tail) { + return JNI_FALSE; + } + v->h->env = env; +#if HAVE_BOTH_SQLITE + if (v->is3) { +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite, v->tail, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) v->h->sqlite, v->tail, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } else { + ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail, + &tail, (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } + } +#else +#if HAVE_SQLITE2 + ret = sqlite_compile((sqlite *) v->h->sqlite, v->tail, + &tail, (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } +#endif +#if HAVE_SQLITE3 +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } +#endif +#endif + if (ret != SQLITE_OK) { + setvmerr(env, obj, ret); + v->tail = 0; + throwex(env, err ? err : "error in compile/prepare"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + return JNI_FALSE; + } +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (!svm) { + v->tail = 0; + return JNI_FALSE; + } + v->vm = svm; + v->tail = (char *) tail; + v->hh.row1 = 1; + return JNI_TRUE; + } + throwex(env, "vm already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_vm_1compile(JNIEnv *env, jobject obj, jstring sql, + jobject vm) +{ +#if HAVE_SQLITE_COMPILE + handle *h = gethandle(env, obj); + void *svm = 0; + hvm *v; + char *err = 0; + const char *tail; + transstr tr; + jvalue vv; + int ret; + jthrowable exc; + + if (!h) { + throwclosed(env); + return; + } + if (!vm) { + throwex(env, "null vm"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } + trans2iso(env, h->haveutf, h->enc, sql, &tr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + h->env = env; +#if HAVE_BOTH_SQLITE + if (h->is3) { +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } else { + ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, + (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + } + } + } +#else +#if HAVE_SQLITE2 + ret = sqlite_compile((sqlite *) h->sqlite, tr.result, &tail, + (sqlite_vm **) &svm, &err); + if (ret != SQLITE_OK) { + if (svm) { + sqlite_finalize((sqlite_vm *) svm, 0); + svm = 0; + } + } +#endif +#if HAVE_SQLITE3 +#if HAVE_SQLITE3_PREPARE_V2 + ret = sqlite3_prepare_v2((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#else + ret = sqlite3_prepare((sqlite3 *) h->sqlite, tr.result, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } +#endif +#endif + if (ret != SQLITE_OK) { + transfree(&tr); + setvmerr(env, vm, ret); + throwex(env, err ? err : "error in prepare/compile"); +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + return; + } +#if HAVE_SQLITE2 + if (err) { + sqlite_freemem(err); + } +#endif + if (!svm) { + transfree(&tr); + return; + } + v = malloc(sizeof (hvm) + strlen(tail) + 1); + if (!v) { + transfree(&tr); +#if HAVE_BOTH_SQLITE + if (h->is3) { + sqlite3_finalize((sqlite3_stmt *) svm); + } else { + sqlite_finalize((sqlite_vm *) svm, 0); + } +#else +#if HAVE_SQLITE2 + sqlite_finalize((sqlite_vm *) svm, 0); +#endif +#if HAVE_SQLITE3 + sqlite3_finalize((sqlite3_stmt *) svm); +#endif +#endif + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = h->is3; +#endif + strcpy(v->tail, tail); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_vm_1compile_1args(JNIEnv *env, + jobject obj, jstring sql, + jobject vm, jobjectArray args) +{ +#if HAVE_SQLITE_COMPILE +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); +#endif + +#if HAVE_BOTH_SQLITE + if (h && !h->is3) { + throwex(env, "unsupported"); + return; + } +#else +#if HAVE_SQLITE2 + throwex(env, "unsupported"); +#endif +#endif +#if HAVE_SQLITE3 + if (!h || !h->sqlite) { + throwclosed(env); + return; + } + if (!vm) { + throwex(env, "null vm"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } else { + void *svm = 0; + hvm *v; + jvalue vv; + jthrowable exc; + jboolean b; + int rc = SQLITE_ERROR, nargs, i; + char *p; + const char *str = (*env)->GetStringUTFChars(env, sql, &b); + const char *tail; + transstr sqlstr; + struct args { + char *arg; + jobject obj; + transstr trans; + } *argv = 0; + char **cargv = 0; + + p = (char *) str; + nargs = 0; + while (*p) { + if (*p == '%') { + ++p; + if (*p == 'q' || *p == 'Q' || *p == 's') { + nargs++; + if (nargs > MAX_PARAMS) { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwex(env, "too much SQL parameters"); + return; + } + } else if (*p != '%') { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwex(env, "bad % specification in query"); + return; + } + } + ++p; + } + cargv = malloc((sizeof (*argv) + sizeof (char *)) * MAX_PARAMS); + if (!cargv) { + (*env)->ReleaseStringUTFChars(env, sql, str); + throwoom(env, "unable to allocate arg vector"); + return; + } + argv = (struct args *) (cargv + MAX_PARAMS); + for (i = 0; i < MAX_PARAMS; i++) { + cargv[i] = 0; + argv[i].arg = 0; + argv[i].obj = 0; + argv[i].trans.result = argv[i].trans.tofree = 0; + } + exc = 0; + for (i = 0; i < nargs; i++) { + jobject so = (*env)->GetObjectArrayElement(env, args, i); + + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + break; + } + if (so) { + argv[i].obj = so; + argv[i].arg = cargv[i] = + trans2iso(env, 1, 0, argv[i].obj, &argv[i].trans); + } + } + if (exc) { + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + (*env)->ReleaseStringUTFChars(env, sql, str); + return; + } + h->row1 = 1; + trans2iso(env, 1, 0, sql, &sqlstr); + exc = (*env)->ExceptionOccurred(env); + if (!exc) { +#if defined(_WIN32) || !defined(CANT_PASS_VALIST_AS_CHARPTR) + char *s = sqlite3_vmprintf(sqlstr.result, (char *) cargv); +#else + char *s = sqlite3_mprintf(sqlstr.result, + cargv[0], cargv[1], + cargv[2], cargv[3], + cargv[4], cargv[5], + cargv[6], cargv[7], + cargv[8], cargv[9], + cargv[10], cargv[11], + cargv[12], cargv[13], + cargv[14], cargv[15], + cargv[16], cargv[17], + cargv[18], cargv[19], + cargv[20], cargv[21], + cargv[22], cargv[23], + cargv[24], cargv[25], + cargv[26], cargv[27], + cargv[28], cargv[29], + cargv[30], cargv[31]); +#endif + if (!s) { + rc = SQLITE_NOMEM; + } else { +#if HAVE_SQLITE3_PREPARE_V2 + rc = sqlite3_prepare_v2((sqlite3 *) h->sqlite, s, -1, + (sqlite3_stmt **) &svm, &tail); +#else + rc = sqlite3_prepare((sqlite3 *) h->sqlite, s, -1, + (sqlite3_stmt **) &svm, &tail); +#endif + if (rc != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + } + if (rc != SQLITE_OK) { + sqlite3_free(s); + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + setvmerr(env, vm, rc); + throwex(env, "error in prepare"); + return; + } + v = malloc(sizeof (hvm) + strlen(tail) + 1); + if (!v) { + sqlite3_free(s); + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + sqlite3_finalize((sqlite3_stmt *) svm); + setvmerr(env, vm, SQLITE_NOMEM); + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = h->is3; +#endif + strcpy(v->tail, tail); + sqlite3_free(s); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, vm, F_SQLite_Vm_handle, vv.j); + } + for (i = 0; i < nargs; i++) { + if (argv[i].obj) { + transfree(&argv[i].trans); + } + } + freep((char **) &cargv); + transfree(&sqlstr); + (*env)->ReleaseStringUTFChars(env, sql, str); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + } + } +#endif +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_FunctionContext_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_FunctionContext_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1progress_1handler(JNIEnv *env, jobject obj, jint n, + jobject ph) +{ + handle *h = gethandle(env, obj); + + if (h && h->sqlite) { + /* CHECK THIS */ +#if HAVE_SQLITE_PROGRESS_HANDLER + delglobrefp(env, &h->ph); +#if HAVE_BOTH_SQLITE + if (h->is3) { + if (ph) { + globrefset(env, ph, &h->ph); + sqlite3_progress_handler((sqlite3 *) h->sqlite, + n, progresshandler, h); + } else { + sqlite3_progress_handler((sqlite3 *) h->sqlite, + 0, 0, 0); + } + } else { + if (ph) { + globrefset(env, ph, &h->ph); + sqlite_progress_handler((sqlite *) h->sqlite, + n, progresshandler, h); + } else { + sqlite_progress_handler((sqlite *) h->sqlite, + 0, 0, 0); + } + } +#else +#if HAVE_SQLITE2 + if (ph) { + globrefset(env, ph, &h->ph); + sqlite_progress_handler((sqlite *) h->sqlite, + n, progresshandler, h); + } else { + sqlite_progress_handler((sqlite *) h->sqlite, + 0, 0, 0); + } +#endif +#if HAVE_SQLITE3 + if (ph) { + globrefset(env, ph, &h->ph); + sqlite3_progress_handler((sqlite3 *) h->sqlite, + n, progresshandler, h); + } else { + sqlite3_progress_handler((sqlite3 *) h->sqlite, + 0, 0, 0); + } +#endif +#endif + return; +#else + throwex(env, "unsupported"); + return; +#endif + } + throwclosed(env); +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Database_is3(JNIEnv *env, jobject obj) +{ +#if HAVE_BOTH_SQLITE + handle *h = gethandle(env, obj); + + if (h) { + return h->is3 ? JNI_TRUE : JNI_FALSE; + } + return JNI_FALSE; +#else +#if HAVE_SQLITE2 + return JNI_FALSE; +#endif +#if HAVE_SQLITE3 + return JNI_TRUE; +#endif +#endif +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Stmt_prepare(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 + hvm *v = gethstmt(env, obj); + void *svm = 0; + char *tail; + int ret; + + if (v && v->vm) { + sqlite3_finalize((sqlite3_stmt *) v->vm); + v->vm = 0; + } + if (v && v->h && v->h->sqlite) { + if (!v->tail) { + return JNI_FALSE; + } + v->h->env = env; +#if HAVE_SQLITE3_PREPARE16_V2 + ret = sqlite3_prepare16_v2((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, + (const void **) &tail); +#else + ret = sqlite3_prepare16((sqlite3 *) v->h->sqlite, + v->tail, -1, (sqlite3_stmt **) &svm, + (const void **) &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + v->tail = 0; + throwex(env, err ? err : "error in compile/prepare"); + return JNI_FALSE; + } + if (!svm) { + v->tail = 0; + return JNI_FALSE; + } + v->vm = svm; + v->tail = (char *) tail; + v->hh.row1 = 1; + return JNI_TRUE; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_stmt_1prepare(JNIEnv *env, jobject obj, jstring sql, + jobject stmt) +{ +#if HAVE_SQLITE3 + handle *h = gethandle(env, obj); + void *svm = 0; + hvm *v; + jvalue vv; + jsize len16; + const jchar *sql16, *tail = 0; + int ret; + + if (!h) { + throwclosed(env); + return; + } + if (!stmt) { + throwex(env, "null stmt"); + return; + } + if (!sql) { + throwex(env, "null sql"); + return; + } +#ifdef HAVE_BOTH_SQLITE + if (!h->is3) { + throwex(env, "only on SQLite3 database"); + return; + } +#endif + len16 = (*env)->GetStringLength(env, sql) * sizeof (jchar); + if (len16 < 1) { + return; + } + h->env = env; + sql16 = (*env)->GetStringChars(env, sql, 0); +#if HAVE_SQLITE3_PREPARE16_V2 + ret = sqlite3_prepare16_v2((sqlite3 *) h->sqlite, sql16, len16, + (sqlite3_stmt **) &svm, (const void **) &tail); +#else + ret = sqlite3_prepare16((sqlite3 *) h->sqlite, sql16, len16, + (sqlite3_stmt **) &svm, (const void **) &tail); +#endif + if (ret != SQLITE_OK) { + if (svm) { + sqlite3_finalize((sqlite3_stmt *) svm); + svm = 0; + } + } + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(h->sqlite); + + (*env)->ReleaseStringChars(env, sql, sql16); + setstmterr(env, stmt, ret); + throwex(env, err ? err : "error in prepare"); + return; + } + if (!svm) { + (*env)->ReleaseStringChars(env, sql, sql16); + return; + } + len16 = len16 + sizeof (jchar) - ((char *) tail - (char *) sql16); + if (len16 < sizeof (jchar)) { + len16 = sizeof (jchar); + } + v = malloc(sizeof (hvm) + len16); + if (!v) { + (*env)->ReleaseStringChars(env, sql, sql16); + sqlite3_finalize((sqlite3_stmt *) svm); + throwoom(env, "unable to get SQLite handle"); + return; + } + v->next = h->vms; + h->vms = v; + v->vm = svm; + v->h = h; + v->tail = (char *) (v + 1); +#if HAVE_BOTH_SQLITE + v->is3 = v->hh.is3 = 1; +#endif + memcpy(v->tail, tail, len16); + len16 /= sizeof (jchar); + ((jchar *) v->tail)[len16 - 1] = 0; + (*env)->ReleaseStringChars(env, sql, sql16); + v->hh.sqlite = 0; + v->hh.haveutf = h->haveutf; + v->hh.ver = h->ver; + v->hh.bh = v->hh.cb = v->hh.ai = v->hh.tr = v->hh.ph = 0; + v->hh.row1 = 1; + v->hh.enc = h->enc; + v->hh.funcs = 0; + v->hh.vms = 0; + v->hh.env = 0; + vv.j = 0; + vv.l = (jobject) v; + (*env)->SetLongField(env, stmt, F_SQLite_Stmt_handle, vv.j); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jboolean JNICALL +Java_SQLite_Stmt_step(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ret; + + ret = sqlite3_step((sqlite3_stmt *) v->vm); + if (ret == SQLITE_ROW) { + return JNI_TRUE; + } + if (ret != SQLITE_DONE) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + throwex(env, err ? err : "error in step"); + } + return JNI_FALSE; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return JNI_FALSE; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_close(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ret; + + ret = sqlite3_finalize((sqlite3_stmt *) v->vm); + v->vm = 0; + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(v->h->sqlite); + + setstmterr(env, obj, ret); + throwex(env, err ? err : "error in close"); + } + return; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_reset(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + sqlite3_reset((sqlite3_stmt *) v->vm); + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_clear_1bindings(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_CLEAR_BINDINGS + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + sqlite3_clear_bindings((sqlite3_stmt *) v->vm); + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__II(JNIEnv *env, jobject obj, jint pos, jint val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_int((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__IJ(JNIEnv *env, jobject obj, jint pos, jlong val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_int64((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__ID(JNIEnv *env, jobject obj, jint pos, jdouble val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_double((sqlite3_stmt *) v->vm, pos, val); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__I_3B(JNIEnv *env, jobject obj, jint pos, jbyteArray val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + jint len; + char *data = 0; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + if (val) { + len = (*env)->GetArrayLength(env, val); + if (len > 0) { + data = sqlite3_malloc(len); + if (!data) { + throwoom(env, "unable to get blob parameter"); + return; + } + (*env)->GetByteArrayRegion(env, val, 0, len, (jbyte *) data); + ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm, + pos, data, len, sqlite3_free); + } else { + ret = sqlite3_bind_blob((sqlite3_stmt *) v->vm, + pos, "", 0, SQLITE_STATIC); + } + } else { + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + } + if (ret != SQLITE_OK) { + if (data) { + sqlite3_free(data); + } + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__ILjava_lang_String_2(JNIEnv *env, jobject obj, + jint pos, jstring val) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + jsize len; + char *data = 0; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + if (val) { + len = (*env)->GetStringLength(env, val); + if (len > 0) { + const jchar *ch; + + len *= sizeof (jchar); + data = sqlite3_malloc(len); + if (!data) { + throwoom(env, "unable to get blob parameter"); + return; + } + ch = (*env)->GetStringChars(env, val, 0); + memcpy(data, ch, len); + (*env)->ReleaseStringChars(env, val, ch); + ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm, + pos, data, len, sqlite3_free); + } else { + ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm, pos, "", 0, + SQLITE_STATIC); + } + } else { + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + } + if (ret != SQLITE_OK) { + if (data) { + sqlite3_free(data); + } + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind__I(JNIEnv *env, jobject obj, jint pos) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_null((sqlite3_stmt *) v->vm, pos); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_bind_1zeroblob(JNIEnv *env, jobject obj, jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_ZEROBLOB + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + int ret; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return; + } + ret = sqlite3_bind_zeroblob((sqlite3_stmt *) v->vm, pos, len); + if (ret != SQLITE_OK) { + setstmterr(env, obj, ret); + throwex(env, "bind failed"); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_bind_1parameter_1count(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + return sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_bind_1parameter_1name(JNIEnv *env, jobject obj, jint pos) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_NAME + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int npar = sqlite3_bind_parameter_count((sqlite3_stmt *) v->vm); + const char *name; + + if (pos < 1 || pos > npar) { + throwex(env, "parameter position out of bounds"); + return 0; + } + name = sqlite3_bind_parameter_name((sqlite3_stmt *) v->vm, pos); + if (name) { + return (*env)->NewStringUTF(env, name); + } + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_bind_1parameter_1index(JNIEnv *env, jobject obj, + jstring name) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_BIND_PARAMETER_INDEX + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int pos; + const char *n; + transstr namestr; + jthrowable exc; + + n = trans2iso(env, 1, 0, name, &namestr); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return -1; + } + pos = sqlite3_bind_parameter_index((sqlite3_stmt *) v->vm, n); + transfree(&namestr); + return pos; + } else { + throwex(env, "stmt already closed"); + } +#else + throwex(env, "unsupported"); +#endif + return -1; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1int(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_int((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jlong JNICALL +Java_SQLite_Stmt_column_1long(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_int64((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jdouble JNICALL +Java_SQLite_Stmt_column_1double(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_double((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jbyteArray JNICALL +Java_SQLite_Stmt_column_1bytes(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + int nbytes; + const jbyte *data; + jbyteArray b = 0; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + data = sqlite3_column_blob((sqlite3_stmt *) v->vm, col); + if (data) { + nbytes = sqlite3_column_bytes((sqlite3_stmt *) v->vm, col); + } else { + return 0; + } + b = (*env)->NewByteArray(env, nbytes); + if (!b) { + throwoom(env, "unable to get blob column data"); + return 0; + } + (*env)->SetByteArrayRegion(env, b, 0, nbytes, data); + return b; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1string(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + int nbytes; + const jchar *data; + jstring b = 0; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + data = sqlite3_column_text16((sqlite3_stmt *) v->vm, col); + if (data) { + nbytes = sqlite3_column_bytes16((sqlite3_stmt *) v->vm, col); + } else { + return 0; + } + nbytes /= sizeof (jchar); + b = (*env)->NewString(env, data, nbytes); + if (!b) { + throwoom(env, "unable to get string column data"); + return 0; + } + return b; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1type(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_data_count((sqlite3_stmt *) v->vm); + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + return sqlite3_column_type((sqlite3_stmt *) v->vm, col); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Stmt_column_1count(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + return sqlite3_column_count((sqlite3_stmt *) v->vm); + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1table_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_TABLE_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_table_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1database_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_DATABASE_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_database_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1decltype(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_decltype16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jstring JNICALL +Java_SQLite_Stmt_column_1origin_1name(JNIEnv *env, jobject obj, jint col) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_COLUMN_ORIGIN_NAME16 + hvm *v = gethstmt(env, obj); + + if (v && v->vm && v->h) { + int ncol = sqlite3_column_count((sqlite3_stmt *) v->vm); + const jchar *str; + + if (col < 0 || col >= ncol) { + throwex(env, "column out of bounds"); + return 0; + } + str = sqlite3_column_origin_name16((sqlite3_stmt *) v->vm, col); + if (str) { + return (*env)->NewString(env, str, jstrlen(str)); + } + return 0; + } + throwex(env, "stmt already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE_COMPILE + dostmtfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Database__1open_1blob(JNIEnv *env, jobject obj, + jstring dbname, jstring table, + jstring column, jlong row, + jboolean rw, jobject blobj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + handle *h = gethandle(env, obj); + hbl *bl; + jthrowable exc; + transstr dbn, tbl, col; + sqlite3_blob *blob; + jvalue vv; + int ret; + + if (!blobj) { + throwex(env, "null blob"); + return; + } + if (h && h->sqlite) { + trans2iso(env, h->haveutf, h->enc, dbname, &dbn); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + (*env)->DeleteLocalRef(env, exc); + return; + } + trans2iso(env, h->haveutf, h->enc, table, &tbl); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + transfree(&dbn); + (*env)->DeleteLocalRef(env, exc); + return; + } + trans2iso(env, h->haveutf, h->enc, column, &col); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + transfree(&tbl); + transfree(&dbn); + (*env)->DeleteLocalRef(env, exc); + return; + } + ret = sqlite3_blob_open(h->sqlite, + dbn.result, tbl.result, col.result, + row, rw, &blob); + transfree(&col); + transfree(&tbl); + transfree(&dbn); + if (ret != SQLITE_OK) { + const char *err = sqlite3_errmsg(h->sqlite); + + seterr(env, obj, ret); + throwex(env, err ? err : "error in blob open"); + return; + } + bl = malloc(sizeof (hbl)); + if (!bl) { + sqlite3_blob_close(blob); + throwoom(env, "unable to get SQLite blob handle"); + return; + } + bl->next = h->blobs; + h->blobs = bl; + bl->blob = blob; + bl->h = h; + vv.j = 0; + vv.l = (jobject) bl; + (*env)->SetLongField(env, blobj, F_SQLite_Blob_handle, vv.j); + (*env)->SetIntField(env, blobj, F_SQLite_Blob_size, + sqlite3_blob_bytes(blob)); + return; + } + throwex(env, "not an open database"); +#else + throwex(env, "unsupported"); +#endif +} + +JNIEXPORT jint JNICALL +Java_SQLite_Blob_write(JNIEnv *env , jobject obj, jbyteArray b, jint off, + jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl = gethbl(env, obj); + + if (bl && bl->h && bl->blob) { + jbyte *buf; + jthrowable exc; + int ret; + + if (len <= 0) { + return 0; + } + buf = malloc(len); + if (!buf) { + throwoom(env, "out of buffer space for blob"); + return 0; + } + (*env)->GetByteArrayRegion(env, b, off, len, buf); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + free(buf); + return 0; + } + ret = sqlite3_blob_write(bl->blob, buf, len, pos); + free(buf); + if (ret != SQLITE_OK) { + throwioex(env, "blob write error"); + return 0; + } + return len; + } + throwex(env, "blob already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT jint JNICALL +Java_SQLite_Blob_read(JNIEnv *env , jobject obj, jbyteArray b, jint off, + jint pos, jint len) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + hbl *bl = gethbl(env, obj); + + if (bl && bl->h && bl->blob) { + jbyte *buf; + jthrowable exc; + int ret; + + if (len <= 0) { + return 0; + } + buf = malloc(len); + if (!buf) { + throwoom(env, "out of buffer space for blob"); + return 0; + } + ret = sqlite3_blob_read(bl->blob, buf, len, pos); + if (ret != SQLITE_OK) { + free(buf); + throwioex(env, "blob read error"); + return 0; + } + (*env)->SetByteArrayRegion(env, b, off, len, buf); + free(buf); + exc = (*env)->ExceptionOccurred(env); + if (exc) { + return 0; + } + return len; + } + throwex(env, "blob already closed"); +#else + throwex(env, "unsupported"); +#endif + return 0; +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_close(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + doblobfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_finalize(JNIEnv *env, jobject obj) +{ +#if HAVE_SQLITE3 && HAVE_SQLITE3_INCRBLOBIO + doblobfinal(env, obj); +#endif +} + +JNIEXPORT void JNICALL +Java_SQLite_Stmt_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Stmt_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Stmt_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Vm_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Vm_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Vm_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Blob_internal_1init(JNIEnv *env, jclass cls) +{ + F_SQLite_Blob_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Blob_size = + (*env)->GetFieldID(env, cls, "size", "I"); +} + +JNIEXPORT void JNICALL +Java_SQLite_Database_internal_1init(JNIEnv *env, jclass cls) +{ +//#ifndef JNI_VERSION_1_2 + jclass jls = (*env)->FindClass(env, "java/lang/String"); + + C_java_lang_String = (*env)->NewGlobalRef(env, jls); +//#endif + F_SQLite_Database_handle = + (*env)->GetFieldID(env, cls, "handle", "J"); + F_SQLite_Database_error_code = + (*env)->GetFieldID(env, cls, "error_code", "I"); + M_java_lang_String_getBytes = + (*env)->GetMethodID(env, C_java_lang_String, "getBytes", "()[B"); + M_java_lang_String_getBytes2 = + (*env)->GetMethodID(env, C_java_lang_String, "getBytes", + "(Ljava/lang/String;)[B"); + M_java_lang_String_initBytes = + (*env)->GetMethodID(env, C_java_lang_String, "<init>", "([B)V"); + M_java_lang_String_initBytes2 = + (*env)->GetMethodID(env, C_java_lang_String, "<init>", + "([BLjava/lang/String;)V"); +} + +#ifdef JNI_VERSION_1_2 +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) +{ + JNIEnv *env; + jclass cls; + +#ifndef _WIN32 +#if HAVE_SQLITE2 + if (strcmp(sqlite_libencoding(), "UTF-8") != 0) { + fprintf(stderr, "WARNING: using non-UTF SQLite2 engine\n"); + } +#endif +#endif + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) { + return JNI_ERR; + } + cls = (*env)->FindClass(env, "java/lang/String"); + if (!cls) { + return JNI_ERR; + } + C_java_lang_String = (*env)->NewWeakGlobalRef(env, cls); + return JNI_VERSION_1_2; +} + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved) +{ + JNIEnv *env; + + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_2)) { + return; + } + if (C_java_lang_String) { + (*env)->DeleteWeakGlobalRef(env, C_java_lang_String); + C_java_lang_String = 0; + } +} +#endif diff --git a/sql/src/main/native/sqlite_jni.h b/sql/src/main/native/sqlite_jni.h new file mode 100644 index 0000000..cdb7692 --- /dev/null +++ b/sql/src/main/native/sqlite_jni.h @@ -0,0 +1,657 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class SQLite_Database */ + +#ifndef _Included_SQLite_Database +#define _Included_SQLite_Database +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Database + * Method: _open + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: SQLite_Database + * Method: _open_aux_file + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open_1aux_1file + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Database + * Method: _finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _exec + * Signature: (Ljava/lang/String;LSQLite/Callback;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2 + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: _exec + * Signature: (Ljava/lang/String;LSQLite/Callback;[Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2 + (JNIEnv *, jobject, jstring, jobject, jobjectArray); + +/* + * Class: SQLite_Database + * Method: _last_insert_rowid + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Database__1last_1insert_1rowid + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _interrupt + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1interrupt + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _changes + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Database__1changes + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _busy_handler + * Signature: (LSQLite/BusyHandler;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1handler + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: _busy_timeout + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1timeout + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Database + * Method: _complete + * Signature: (Ljava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Database__1complete + (JNIEnv *, jclass, jstring); + +/* + * Class: SQLite_Database + * Method: version + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_version + (JNIEnv *, jclass); + +/* + * Class: SQLite_Database + * Method: dbversion + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_dbversion + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: _create_function + * Signature: (Ljava/lang/String;ILSQLite/Function;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1create_1function + (JNIEnv *, jobject, jstring, jint, jobject); + +/* + * Class: SQLite_Database + * Method: _create_aggregate + * Signature: (Ljava/lang/String;ILSQLite/Function;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1create_1aggregate + (JNIEnv *, jobject, jstring, jint, jobject); + +/* + * Class: SQLite_Database + * Method: _function_type + * Signature: (Ljava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1function_1type + (JNIEnv *, jobject, jstring, jint); + +/* + * Class: SQLite_Database + * Method: _errmsg + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database__1errmsg + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: error_string + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Database_error_1string + (JNIEnv *, jclass, jint); + +/* + * Class: SQLite_Database + * Method: _set_encoding + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1set_1encoding + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Database + * Method: _set_authorizer + * Signature: (LSQLite/Authorizer;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1set_1authorizer + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: _trace + * Signature: (LSQLite/Trace;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1trace + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Database + * Method: is3 + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Database_is3 + (JNIEnv *, jobject); + +/* + * Class: SQLite_Database + * Method: vm_compile + * Signature: (Ljava/lang/String;LSQLite/Vm;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: vm_compile_args + * Signature: (Ljava/lang/String;LSQLite/Vm;[Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile_1args + (JNIEnv *, jobject, jstring, jobject, jobjectArray); + +/* + * Class: SQLite_Database + * Method: stmt_prepare + * Signature: (Ljava/lang/String;LSQLite/Stmt;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_stmt_1prepare + (JNIEnv *, jobject, jstring, jobject); + +/* + * Class: SQLite_Database + * Method: _open_blob + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZLSQLite/Blob;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1open_1blob + (JNIEnv *, jobject, jstring, jstring, jstring, jlong, jboolean, jobject); + +/* + * Class: SQLite_Database + * Method: _progress_handler + * Signature: (ILSQLite/ProgressHandler;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Database__1progress_1handler + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: SQLite_Database + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Database_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Vm */ + +#ifndef _Included_SQLite_Vm +#define _Included_SQLite_Vm +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Vm + * Method: step + * Signature: (LSQLite/Callback;)Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Vm_step + (JNIEnv *, jobject, jobject); + +/* + * Class: SQLite_Vm + * Method: compile + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Vm_compile + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: stop + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_stop + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Vm + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Vm_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_FunctionContext */ + +#ifndef _Included_SQLite_FunctionContext +#define _Included_SQLite_FunctionContext +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2 + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__I + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: (D)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__D + (JNIEnv *, jobject, jdouble); + +/* + * Class: SQLite_FunctionContext + * Method: set_error + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1error + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_FunctionContext + * Method: set_result + * Signature: ([B)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result___3B + (JNIEnv *, jobject, jbyteArray); + +/* + * Class: SQLite_FunctionContext + * Method: set_result_zeroblob + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result_1zeroblob + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_FunctionContext + * Method: count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_FunctionContext_count + (JNIEnv *, jobject); + +/* + * Class: SQLite_FunctionContext + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_FunctionContext_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Stmt */ + +#ifndef _Included_SQLite_Stmt +#define _Included_SQLite_Stmt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Stmt + * Method: prepare + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_prepare + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: step + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_step + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: reset + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_reset + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: clear_bindings + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_clear_1bindings + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__II + (JNIEnv *, jobject, jint, jint); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (IJ)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__IJ + (JNIEnv *, jobject, jint, jlong); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (ID)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ID + (JNIEnv *, jobject, jint, jdouble); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (I[B)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I_3B + (JNIEnv *, jobject, jint, jbyteArray); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ILjava_lang_String_2 + (JNIEnv *, jobject, jint, jstring); + +/* + * Class: SQLite_Stmt + * Method: bind + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_zeroblob + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_bind_1zeroblob + (JNIEnv *, jobject, jint, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1count + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_bind_1parameter_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: bind_parameter_index + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1index + (JNIEnv *, jobject, jstring); + +/* + * Class: SQLite_Stmt + * Method: column_int + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1int + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_long + * Signature: (I)J + */ +JNIEXPORT jlong JNICALL Java_SQLite_Stmt_column_1long + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_double + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_SQLite_Stmt_column_1double + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_bytes + * Signature: (I)[B + */ +JNIEXPORT jbyteArray JNICALL Java_SQLite_Stmt_column_1bytes + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_string + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1string + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_type + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1type + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_count + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1count + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: column_table_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1table_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_database_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1database_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_decltype + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1decltype + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: column_origin_name + * Signature: (I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1origin_1name + (JNIEnv *, jobject, jint); + +/* + * Class: SQLite_Stmt + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Stmt + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Stmt_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class SQLite_Blob */ + +#ifndef _Included_SQLite_Blob +#define _Included_SQLite_Blob +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: SQLite_Blob + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_close + (JNIEnv *, jobject); + +/* + * Class: SQLite_Blob + * Method: write + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Blob_write + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: SQLite_Blob + * Method: read + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_SQLite_Blob_read + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: SQLite_Blob + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_finalize + (JNIEnv *, jobject); + +/* + * Class: SQLite_Blob + * Method: internal_init + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_SQLite_Blob_internal_1init + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/sql/src/main/native/sqlite_jni_defs.h b/sql/src/main/native/sqlite_jni_defs.h new file mode 100644 index 0000000..91b2378 --- /dev/null +++ b/sql/src/main/native/sqlite_jni_defs.h @@ -0,0 +1,39 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define HAVE_SQLITE2 0 +#define HAVE_SQLITE3 1 +#define HAVE_SQLITE_FUNCTION_TYPE 0 +#define HAVE_SQLITE_OPEN_AUX_FILE 0 +#define HAVE_SQLITE_SET_AUTHORIZER 0 +#define HAVE_SQLITE_TRACE 0 +#define HAVE_SQLITE_COMPILE 0 +#define HAVE_SQLITE_PROGRESS_HANDLER 0 +#define HAVE_SQLITE3_MALLOC 1 +#define HAVE_SQLITE3_PREPARE_V2 0 +#define HAVE_SQLITE3_PREPARE16_V2 0 +#define HAVE_SQLITE3_BIND_ZEROBLOB 0 +#define HAVE_SQLITE3_CLEAR_BINDINGS 0 +#define HAVE_SQLITE3_COLUMN_TABLE_NAME16 0 +#define HAVE_SQLITE3_COLUMN_DATABASE_NAME16 0 +#define HAVE_SQLITE3_COLUMN_ORIGIN_NAME16 0 +#define HAVE_SQLITE3_BIND_PARAMETER_COUNT 1 +#define HAVE_SQLITE3_BIND_PARAMETER_NAME 1 +#define HAVE_SQLITE3_BIND_PARAMETER_INDEX 1 +#define HAVE_SQLITE3_RESULT_ZEROBLOB 0 +#define HAVE_SQLITE3_INCRBLOBIO 0 + + diff --git a/sql/src/main/native/sqlite_jni_registration.c b/sql/src/main/native/sqlite_jni_registration.c new file mode 100644 index 0000000..1ef5192 --- /dev/null +++ b/sql/src/main/native/sqlite_jni_registration.c @@ -0,0 +1,308 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "JNIHelp.h" +#include "sqlite_jni.h" + +/* Methods for class SQLite_Database */ +extern JNIEXPORT void JNICALL Java_SQLite_Database__1open + (JNIEnv *, jobject, jstring, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1open_1aux_1file + (JNIEnv *, jobject, jstring); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1finalize + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1close + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2 + (JNIEnv *, jobject, jstring, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2 + (JNIEnv *, jobject, jstring, jobject, jobjectArray); +extern JNIEXPORT jlong JNICALL Java_SQLite_Database__1last_1insert_1rowid + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1interrupt + (JNIEnv *, jobject); +extern JNIEXPORT jlong JNICALL Java_SQLite_Database__1changes + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1handler + (JNIEnv *, jobject, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1busy_1timeout + (JNIEnv *, jobject, jint); +extern JNIEXPORT jboolean JNICALL Java_SQLite_Database__1complete + (JNIEnv *, jclass, jstring); +extern JNIEXPORT jstring JNICALL Java_SQLite_Database_version + (JNIEnv *, jclass); +extern JNIEXPORT jstring JNICALL Java_SQLite_Database_dbversion + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1create_1function + (JNIEnv *, jobject, jstring, jint, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1create_1aggregate + (JNIEnv *, jobject, jstring, jint, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1function_1type + (JNIEnv *, jobject, jstring, jint); +extern JNIEXPORT jstring JNICALL Java_SQLite_Database__1errmsg + (JNIEnv *, jobject); +extern JNIEXPORT jstring JNICALL Java_SQLite_Database_error_1string + (JNIEnv *, jclass, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1set_1encoding + (JNIEnv *, jobject, jstring); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1set_1authorizer + (JNIEnv *, jobject, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1trace + (JNIEnv *, jobject, jobject); +extern JNIEXPORT jboolean JNICALL Java_SQLite_Database_is3 + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile + (JNIEnv *, jobject, jstring, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database_vm_1compile_1args + (JNIEnv *, jobject, jstring, jobject, jobjectArray); +extern JNIEXPORT void JNICALL Java_SQLite_Database_stmt_1prepare + (JNIEnv *, jobject, jstring, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1open_1blob + (JNIEnv *, jobject, jstring, jstring, jstring, jlong, jboolean, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database__1progress_1handler + (JNIEnv *, jobject, jint, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Database_internal_1init + (JNIEnv *, jclass); + + +/* Methods for class SQLite_Vm */ + +extern JNIEXPORT jboolean JNICALL Java_SQLite_Vm_step + (JNIEnv *, jobject, jobject); +extern JNIEXPORT jboolean JNICALL Java_SQLite_Vm_compile + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Vm_stop + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Vm_finalize + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Vm_internal_1init + (JNIEnv *, jclass); + +/* Methods for class SQLite_FunctionContext */ + +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2 + (JNIEnv *, jobject, jstring); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__I + (JNIEnv *, jobject, jint); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result__D + (JNIEnv *, jobject, jdouble); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1error + (JNIEnv *, jobject, jstring); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result___3B + (JNIEnv *, jobject, jbyteArray); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_set_1result_1zeroblob + (JNIEnv *, jobject, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_FunctionContext_count + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_FunctionContext_internal_1init + (JNIEnv *, jclass); + +/* Methods for class SQLite_Stmt */ + +extern JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_prepare + (JNIEnv *, jobject); +extern JNIEXPORT jboolean JNICALL Java_SQLite_Stmt_step + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_close + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_reset + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_clear_1bindings + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__II + (JNIEnv *, jobject, jint, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__IJ + (JNIEnv *, jobject, jint, jlong); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ID + (JNIEnv *, jobject, jint, jdouble); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I_3B + (JNIEnv *, jobject, jint, jbyteArray); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__ILjava_lang_String_2 + (JNIEnv *, jobject, jint, jstring); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind__I + (JNIEnv *, jobject, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_bind_1zeroblob + (JNIEnv *, jobject, jint, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1count + (JNIEnv *, jobject); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_bind_1parameter_1name + (JNIEnv *, jobject, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_Stmt_bind_1parameter_1index + (JNIEnv *, jobject, jstring); +extern JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1int + (JNIEnv *, jobject, jint); +extern JNIEXPORT jlong JNICALL Java_SQLite_Stmt_column_1long + (JNIEnv *, jobject, jint); +extern JNIEXPORT jdouble JNICALL Java_SQLite_Stmt_column_1double + (JNIEnv *, jobject, jint); +extern JNIEXPORT jbyteArray JNICALL Java_SQLite_Stmt_column_1bytes + (JNIEnv *, jobject, jint); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1string + (JNIEnv *, jobject, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1type + (JNIEnv *, jobject, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_Stmt_column_1count + (JNIEnv *, jobject); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1table_1name + (JNIEnv *, jobject, jint); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1database_1name + (JNIEnv *, jobject, jint); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1decltype + (JNIEnv *, jobject, jint); +extern JNIEXPORT jstring JNICALL Java_SQLite_Stmt_column_1origin_1name + (JNIEnv *, jobject, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_finalize + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Stmt_internal_1init + (JNIEnv *, jclass); + +/* Methods for class SQLite_Blob */ + +extern JNIEXPORT void JNICALL Java_SQLite_Blob_close + (JNIEnv *, jobject); +extern JNIEXPORT jint JNICALL Java_SQLite_Blob_write + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); +extern JNIEXPORT jint JNICALL Java_SQLite_Blob_read + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); +extern JNIEXPORT void JNICALL Java_SQLite_Blob_finalize + (JNIEnv *, jobject); +extern JNIEXPORT void JNICALL Java_SQLite_Blob_internal_1init + (JNIEnv *, jclass); + +/* + * JNI registration + */ +static JNINativeMethod sqliteDatabaseMethods[] = { + /* name, signature, funcPtr */ +/* Header for class SQLite_Database */ +{ "_open", "(Ljava/lang/String;I)V", Java_SQLite_Database__1open}, +{ "_open_aux_file", "(Ljava/lang/String;)V", Java_SQLite_Database__1open_1aux_1file}, +{ "_finalize", "()V", Java_SQLite_Database__1finalize}, +{ "_close", "()V", Java_SQLite_Database__1close}, +{ "_exec", "(Ljava/lang/String;LSQLite/Callback;)V", Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2}, +{ "_exec", "(Ljava/lang/String;LSQLite/Callback;[Ljava/lang/String;)V", Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_String_2}, +{ "_last_insert_rowid", "()J", Java_SQLite_Database__1last_1insert_1rowid}, +{ "_interrupt", "()V", Java_SQLite_Database__1interrupt}, +{ "_changes", "()J", Java_SQLite_Database__1changes}, +{ "_busy_handler", "(LSQLite/BusyHandler;)V", Java_SQLite_Database__1busy_1handler}, +{ "_busy_timeout", "(I)V", Java_SQLite_Database__1busy_1timeout}, +{ "_complete", "(Ljava/lang/String;)Z", Java_SQLite_Database__1complete}, +{ "version", "()Ljava/lang/String;", Java_SQLite_Database_version}, +{ "dbversion", "()Ljava/lang/String;", Java_SQLite_Database_dbversion}, +{ "_create_function", "(Ljava/lang/String;ILSQLite/Function;)V", Java_SQLite_Database__1create_1function}, +{ "_create_aggregate", "(Ljava/lang/String;ILSQLite/Function;)V", Java_SQLite_Database__1create_1aggregate}, +{ "_function_type", "(Ljava/lang/String;I)V", Java_SQLite_Database__1function_1type}, +{ "_errmsg", "()Ljava/lang/String;", Java_SQLite_Database__1errmsg}, +{ "error_string", "(I)Ljava/lang/String;", Java_SQLite_Database_error_1string}, +{ "_set_encoding", "(Ljava/lang/String;)V", Java_SQLite_Database__1set_1encoding}, +{ "_set_authorizer", "(LSQLite/Authorizer;)V", Java_SQLite_Database__1set_1authorizer}, +{ "_trace", "(LSQLite/Trace;)V", Java_SQLite_Database__1trace}, +{ "is3", "()Z", Java_SQLite_Database_is3}, +{ "vm_compile", "(Ljava/lang/String;LSQLite/Vm;)V", Java_SQLite_Database_vm_1compile}, +{ "vm_compile_args", "(Ljava/lang/String;LSQLite/Vm;[Ljava/lang/String;)V", Java_SQLite_Database_vm_1compile_1args}, +{ "stmt_prepare", "(Ljava/lang/String;LSQLite/Stmt;)V", Java_SQLite_Database_stmt_1prepare}, +{ "_open_blob", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZLSQLite/Blob;)V", Java_SQLite_Database__1open_1blob}, +{ "_progress_handler", "(ILSQLite/ProgressHandler;)V", Java_SQLite_Database__1progress_1handler}, +{ "internal_init", "()V", Java_SQLite_Database_internal_1init} +}; + +static JNINativeMethod sqliteVmMethods[] = { +/* Header for class SQLite_Vm */ +{ "step", "(LSQLite/Callback;)Z", Java_SQLite_Vm_step}, +{ "compile", "()Z", Java_SQLite_Vm_compile}, +{ "stop", "()V", Java_SQLite_Vm_stop}, +{ "finalize", "()V", Java_SQLite_Vm_finalize}, +{ "internal_init", "()V", Java_SQLite_Vm_internal_1init} +}; + +static JNINativeMethod sqliteFunctionContextMethods[] = { +/* Header for class SQLite_FunctionContext */ +{ "set_result", "(Ljava/lang/String;)V", Java_SQLite_FunctionContext_set_1result__Ljava_lang_String_2}, +{ "set_result", "(I)V", Java_SQLite_FunctionContext_set_1result__I}, +{ "set_result", "(D)V", Java_SQLite_FunctionContext_set_1result__D}, +{ "set_error", "(Ljava/lang/String;)V", Java_SQLite_FunctionContext_set_1error}, +{ "set_result", "([B)V", Java_SQLite_FunctionContext_set_1result___3B}, +{ "set_result_zeroblob", "(I)V", Java_SQLite_FunctionContext_set_1result_1zeroblob}, +{ "count", "()I", Java_SQLite_FunctionContext_count}, +{ "internal_init", "()V", Java_SQLite_FunctionContext_internal_1init} +}; + +static JNINativeMethod sqliteStmtMethods[] = { +/* Header for class SQLite_Stmt */ +{ "prepare", "()Z", Java_SQLite_Stmt_prepare}, +{ "step", "()Z", JNICALL Java_SQLite_Stmt_step}, +{ "close", "()V", Java_SQLite_Stmt_close}, +{ "reset", "()V", Java_SQLite_Stmt_reset}, +{ "clear_bindings", "()V", Java_SQLite_Stmt_clear_1bindings}, +{ "bind", "(II)V", Java_SQLite_Stmt_bind__II}, +{ "bind", "(IJ)V", Java_SQLite_Stmt_bind__IJ}, +{ "bind", "(ID)V", Java_SQLite_Stmt_bind__ID}, +{ "bind", "(I[B)V", Java_SQLite_Stmt_bind__I_3B}, +{ "bind", "(ILjava/lang/String;)V", Java_SQLite_Stmt_bind__ILjava_lang_String_2}, +{ "bind", "(I)V", Java_SQLite_Stmt_bind__I}, +{ "bind_zeroblob", "(II)V", Java_SQLite_Stmt_bind_1zeroblob}, +{ "bind_parameter_count", "()I", Java_SQLite_Stmt_bind_1parameter_1count}, +{ "bind_parameter_name", "(I)Ljava/lang/String;", Java_SQLite_Stmt_bind_1parameter_1name}, +{ "bind_parameter_index", "(Ljava/lang/String;)I", Java_SQLite_Stmt_bind_1parameter_1index}, +{ "column_int", "(I)I", Java_SQLite_Stmt_column_1int}, +{ "column_long", "(I)J", Java_SQLite_Stmt_column_1long}, +{ "column_double", "(I)D", Java_SQLite_Stmt_column_1double}, +{ "column_bytes", "(I)[B", Java_SQLite_Stmt_column_1bytes}, +{ "column_string", "(I)Ljava/lang/String;", Java_SQLite_Stmt_column_1string}, +{ "column_type", "(I)I", Java_SQLite_Stmt_column_1type}, +{ "column_count", "()I", Java_SQLite_Stmt_column_1count}, +{ "column_table_name", "(I)Ljava/lang/String;", Java_SQLite_Stmt_column_1table_1name}, +{ "column_database_name", "(I)Ljava/lang/String;", Java_SQLite_Stmt_column_1database_1name}, +{ "column_decltype", "(I)Ljava/lang/String;", Java_SQLite_Stmt_column_1decltype}, +{ "column_origin_name", "(I)Ljava/lang/String;", Java_SQLite_Stmt_column_1origin_1name}, +{ "finalize", "()V", Java_SQLite_Stmt_finalize}, +{ "internal_init", "()V", Java_SQLite_Stmt_internal_1init} +}; + +static JNINativeMethod sqliteBlobMethods[] = { +/* Header for class SQLite_Blob */ + +{ "close", "()V", Java_SQLite_Blob_close}, +{ "write", "([BIII)I", Java_SQLite_Blob_write}, +{ "read", "([BIII)I", Java_SQLite_Blob_read}, +{ "finalize", "()V", Java_SQLite_Blob_finalize}, +{ "internal_init", "()V", Java_SQLite_Blob_internal_1init} +}; + +int register_SQLite_Database(JNIEnv* env) { + return jniRegisterNativeMethods(env, "SQLite/Database", + sqliteDatabaseMethods, NELEM(sqliteDatabaseMethods)); +} + +int register_SQLite_Vm(JNIEnv* env) { + return jniRegisterNativeMethods(env, "SQLite/Vm", + sqliteVmMethods, NELEM(sqliteVmMethods)); +} + +int register_SQLite_FunctionContext(JNIEnv* env) { + return jniRegisterNativeMethods(env, "SQLite/FunctionContext", + sqliteFunctionContextMethods, NELEM(sqliteFunctionContextMethods)); +} + +int register_SQLite_Stmt(JNIEnv* env) { + return jniRegisterNativeMethods(env, "SQLite/Stmt", + sqliteStmtMethods, NELEM(sqliteStmtMethods)); +} + +int register_SQLite_Blob(JNIEnv* env) { + return jniRegisterNativeMethods(env, "SQLite/Blob", + sqliteBlobMethods, NELEM(sqliteBlobMethods)); +} diff --git a/sql/src/main/native/sub.mk b/sql/src/main/native/sub.mk new file mode 100644 index 0000000..d84e0b6 --- /dev/null +++ b/sql/src/main/native/sub.mk @@ -0,0 +1,19 @@ +# This file is included by the top-level libcore Android.mk. +# It's not a normal makefile, so we don't include CLEAR_VARS +# or BUILD_*_LIBRARY. + +LOCAL_SRC_FILES := \ + sqlite_jni.c \ + sqlite_jni_registration.c + +LOCAL_C_INCLUDES += \ + external/sqlite/dist + +# Any shared/static libs that are listed here must also +# be listed in libs/nativehelper/Android.mk. +# TODO: fix this requirement + +LOCAL_SHARED_LIBRARIES += \ + libsqlite + +LOCAL_STATIC_LIBRARIES += diff --git a/sql/src/test/java/SQLite/JDBCDriverTest.java b/sql/src/test/java/SQLite/JDBCDriverTest.java new file mode 100644 index 0000000..cc4d769 --- /dev/null +++ b/sql/src/test/java/SQLite/JDBCDriverTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package SQLite; + +import tests.sql.AbstractSqlTest; + +import java.io.File; +import java.sql.Connection; +import java.sql.SQLException; + + + +/** + * Tests the SQLite.JDBCDriver. + */ +public class JDBCDriverTest extends AbstractSqlTest { + + + + /** + * The SQLite db file. + */ + private final File dbFile = new File("sqliteTest.db"); + + private final String connectionURL = "jdbc:sqlite:/" + dbFile.getName(); + + /** + * Creates a new instance of this class. + */ + public JDBCDriverTest(String testName) { + super(testName); + } + + /** + * Sets up an unit test by loading the SQLite.JDBCDriver, getting two + * connections and calling the setUp method of the super class. + */ + @Override + protected void setUp() throws ClassNotFoundException, SQLException, + java.lang.Exception { // the Exception class needs to be fully + // qualified since there is an Exception + // class in the SQLite package. + + super.setUp(); + } + + /** + * Tears down an unit test by calling the tearDown method of the super class + * and deleting the SQLite test db file. + */ + @Override + protected void tearDown() throws SQLException { + super.tearDown(); + dbFile.delete(); + } + + + @Override + protected String getConnectionURL() { + return connectionURL; + } + + @Override + protected String getDriverClassName() { + return "SQLite.JDBCDriver"; + } + + @Override + protected int getTransactionIsolation() { + return Connection.TRANSACTION_SERIALIZABLE; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/AllTests.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/AllTests.java new file mode 100644 index 0000000..6dc7c84 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/AllTests.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * This is autogenerated source file. Includes tests for package org.apache.harmony.sql.tests.java.sql; + */ + +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = new TestSuite("All tests for package org.apache.harmony.sql.tests.java.sql;"); + // $JUnit-BEGIN$ + + suite.addTestSuite(BatchUpdateExceptionTest.class); + suite.addTestSuite(ConnectionTest.class); + suite.addTestSuite(DataTruncationTest.class); + suite.addTestSuite(DatabaseMetaDataTest.class); + suite.addTestSuite(DateTest.class); + suite.addTestSuite(DriverManagerTest.class); + suite.addTestSuite(DriverPropertyInfoTest.class); + suite.addTestSuite(ParameterMetaDataTest.class); + suite.addTestSuite(ResultSetMetaDataTest.class); + suite.addTestSuite(ResultSetTest.class); + suite.addTestSuite(SQLExceptionTest.class); + suite.addTestSuite(SQLPermissionTest.class); + suite.addTestSuite(SQLWarningTest.class); + suite.addTestSuite(StatementTest.class); + suite.addTestSuite(TimeTest.class); + suite.addTestSuite(TimestampTest.class); + suite.addTestSuite(TypesTest.class); + + // $JUnit-END$ + return suite; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.java new file mode 100644 index 0000000..241888a --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.java @@ -0,0 +1,384 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.Serializable; +import java.sql.BatchUpdateException; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; + +public class BatchUpdateExceptionTest extends TestCase { + + /* + * ConstructorTest + */ + public void testBatchUpdateException() { + + int[] theFinalStates1 = { 0 }; // Error Code state + int[][] theFinalStates2 = { null }; // Update Counts array state + String[] theFinalStates3 = { null }; // SQL State state value + String[] theFinalStates4 = { null }; // Message state + + Exception[] theExceptions = { null }; + + BatchUpdateException aBatchUpdateException; + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testBatchUpdateException + + /* + * ConstructorTest + */ + public void testBatchUpdateExceptionintArray() { + + int[][] init1 = { { 1, 2, 3 }, null }; + + int[] theFinalStates1 = { 0, 0 }; // Error Code state + int[][] theFinalStates2 = init1; // Update Counts array state + String[] theFinalStates3 = { null, null }; // SQL State state value + String[] theFinalStates4 = { null, null }; // Message state + + Exception[] theExceptions = { null, null }; + + BatchUpdateException aBatchUpdateException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(init1[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testBatchUpdateExceptionintArray + + /* + * ConstructorTest + */ + public void testBatchUpdateExceptionStringintArray() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, "", + ".", "a" }; + int[][] init2 = { { 1, 2, 3 }, {}, { 3 }, null, { 5, 5 }, { 6 }, + { 121, 2, 1 }, { 1 }, { 1, 2 } }; + + int[] theFinalStates1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Error Code + // state + // Update Counts array state + int[][] theFinalStates2 = init2; + // SQL State state value + String[] theFinalStates3 = { null, null, null, null, null, null, null, + null, null }; + String[] theFinalStates4 = init1; // Message state + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null }; + + BatchUpdateException aBatchUpdateException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(init1[i], + init2[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testBatchUpdateExceptionStringintArray + + /* + * ConstructorTest + */ + public void testBatchUpdateExceptionStringStringintArray() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, "", + ".", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "a", null, + "", ".", "a" }; + int[][] init3 = { { 1, 2, 3 }, {}, { 3 }, { 5, 5 }, { 6 }, + { 121, 2, 1 }, { 1 }, { 1, 2 }, { 1 }, { 2 }, null }; + + int[] theFinalStates1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Error + // Code + // state + // Update Counts array state + int[][] theFinalStates2 = init3; + // SQL State state value + String[] theFinalStates3 = init2; + String[] theFinalStates4 = init1; // Message state + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null }; + + BatchUpdateException aBatchUpdateException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(init1[i], + init2[i], init3[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testBatchUpdateExceptionStringStringintArray + + /* + * ConstructorTest + */ + public void testBatchUpdateExceptionStringStringintintArray() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, "", + ".", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "a", null, + "", ".", "a" }; + int[] init3 = { -2147483648, 2147483647, 0, -492417162, -156220255, + -173012890, -631026360, -2147483648, -2147483648, -2147483648, + -2147483648 }; + int[][] init4 = { { 1, 2, 3 }, {}, { 3 }, { 5, 5 }, { 6 }, + { 121, 2, 1 }, { 1 }, { 1, 2 }, { 1 }, { 2 }, null }; + + int[] theFinalStates1 = init3; // Error Code state + // Update Counts array state + int[][] theFinalStates2 = init4; + // SQL State state value + String[] theFinalStates3 = init2; + String[] theFinalStates4 = init1; // Message state + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null }; + + BatchUpdateException aBatchUpdateException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(init1[i], + init2[i], init3[i], init4[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testBatchUpdateExceptionStringStringintintArray + + /* + * Method test for getUpdateCounts + */ + public void testGetUpdateCounts() { + + BatchUpdateException aBatchUpdateException; + int[][] init1 = { { 1, 2, 3 }, {}, null }; + + int[] theReturn; + int[][] theReturns = init1; + + int[] theFinalStates1 = { 0, 0, 0 }; // Error Code state + int[][] theFinalStates2 = init1; // Update Counts array state + String[] theFinalStates3 = { null, null, null }; // SQL State state + // value + String[] theFinalStates4 = { null, null, null }; // Message state + + Exception[] theExceptions = { null, null, null }; + + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aBatchUpdateException = new BatchUpdateException(init1[i]); + theReturn = aBatchUpdateException.getUpdateCounts(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getErrorCode(), + theFinalStates1[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getUpdateCounts(), + theFinalStates2[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getSQLState(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch: ", + aBatchUpdateException.getMessage(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetUpdateCounts + + /** + * @tests serialization/deserialization compatibility. + */ + public void testSerializationSelf() throws Exception { + BatchUpdateException object = new BatchUpdateException(); + SerializationTest.verifySelf(object, BATCHUPDATEEXCEPTION_COMPARATOR); + } + + /** + * @tests serialization/deserialization compatibility with RI. + */ + public void testSerializationCompatibility() throws Exception { + int vendorCode = 10; + int[] updateCounts = { 1, 2, 3, 4 }; + BatchUpdateException object = new BatchUpdateException("reason", + "SQLState", vendorCode, updateCounts); + SerializationTest.verifyGolden(this, object, + BATCHUPDATEEXCEPTION_COMPARATOR); + } + + // comparator for BatchUpdateException field updateCounts + private static final SerializableAssert BATCHUPDATEEXCEPTION_COMPARATOR = new SerializableAssert() { + public void assertDeserialized(Serializable initial, + Serializable deserialized) { + + // do common checks for all throwable objects + SerializationTest.THROWABLE_COMPARATOR.assertDeserialized(initial, + deserialized); + + BatchUpdateException initThr = (BatchUpdateException) initial; + BatchUpdateException dserThr = (BatchUpdateException) deserialized; + + // verify updateCounts + int[] initUpdateCounts = initThr.getUpdateCounts(); + int[] dserUpdateCounts = dserThr.getUpdateCounts(); + assertTrue(Arrays.equals(initUpdateCounts, dserUpdateCounts)); + } + }; + +} // end class BatchUpdateExceptionTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ConnectionTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ConnectionTest.java new file mode 100644 index 0000000..22409f7 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ConnectionTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class ConnectionTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("TRANSACTION_SERIALIZABLE", new Integer(8)); + thePublicStatics.put("TRANSACTION_REPEATABLE_READ", new Integer(4)); + thePublicStatics.put("TRANSACTION_READ_COMMITTED", new Integer(2)); + thePublicStatics.put("TRANSACTION_READ_UNCOMMITTED", new Integer(1)); + thePublicStatics.put("TRANSACTION_NONE", new Integer(0)); + + /* + * System.out.println( "TRANSACTION_SERIALIZABLE: " + + * Connection.TRANSACTION_SERIALIZABLE ); System.out.println( + * "TRANSACTION_REPEATABLE_READ: " + + * Connection.TRANSACTION_REPEATABLE_READ ); System.out.println( + * "TRANSACTION_READ_COMMITTED: " + + * Connection.TRANSACTION_READ_COMMITTED ); System.out.println( + * "TRANSACTION_READ_UNCOMMITTED: " + + * Connection.TRANSACTION_READ_UNCOMMITTED ); System.out.println( + * "TRANSACTION_NONE: " + Connection.TRANSACTION_NONE ); + */ + + Class<?> connectionClass; + try { + connectionClass = Class.forName("java.sql.Connection"); + } catch (ClassNotFoundException e) { + fail("java.sql.Connection class not found!"); + return; + } // end try + + Field[] theFields = connectionClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class ConnectionTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.java new file mode 100644 index 0000000..624da41 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.java @@ -0,0 +1,501 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.Serializable; +import java.sql.DataTruncation; +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; + +import junit.framework.TestCase; + +public class DataTruncationTest extends TestCase { + + /* + * ConstructorTest + */ + public void testDataTruncationintbooleanbooleanintint() { + + int[] init1 = { -2147483648, 2147483647, 0, 329751502, 318587557, + -1217247045, 329474146 }; + boolean[] init2 = { false, true, false, false, false, true, false }; + boolean[] init3 = { false, true, false, false, false, false, true }; + int[] init4 = { -2147483648, 2147483647, 0, 1761409290, -1331044048, + -576231606, 661635011 }; + int[] init5 = { -2147483648, 2147483647, 0, 540816689, -1890783845, + -105552912, -85923935 }; + + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + DataTruncation aDataTruncation; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testDataTruncationintbooleanbooleanintint + + /* + * Method test for getIndex + */ + public void testGetIndex() { + + DataTruncation aDataTruncation; + int[] init1 = { -2147483648, 2147483647, 0, -2045829673, 1977156911, + 478985827, 1687271915 }; + boolean[] init2 = { false, true, false, false, true, true, true }; + boolean[] init3 = { false, true, false, false, true, true, true }; + int[] init4 = { -2147483648, 2147483647, 0, -631377748, 21025030, + 1215194589, 1064137121 }; + int[] init5 = { -2147483648, 2147483647, 0, -897998505, 997578180, + 735015866, 264619424 }; + + int theReturn; + int[] theReturns = init1; + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + theReturn = aDataTruncation.getIndex(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetIndex + + /* + * Method test for getParameter + */ + public void testGetParameter() { + + DataTruncation aDataTruncation; + int[] init1 = { -2147483648, 2147483647, 0, -492314242, 1637665948, + -305785075, 258819883 }; + boolean[] init2 = { false, true, false, true, true, false, true }; + boolean[] init3 = { false, true, false, false, false, true, true }; + int[] init4 = { -2147483648, 2147483647, 0, 1134512579, 533874007, + 1709608139, 990656593 }; + int[] init5 = { -2147483648, 2147483647, 0, -1566784226, -744009101, + -444614454, 356465980 }; + + boolean theReturn; + boolean[] theReturns = init2; + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + theReturn = aDataTruncation.getParameter(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetParameter + + /* + * Method test for getRead + */ + public void testGetRead() { + + DataTruncation aDataTruncation; + int[] init1 = { -2147483648, 2147483647, 0, 2092420209, -1695764964, + 1832837995, -80199594 }; + boolean[] init2 = { false, true, false, false, false, true, true }; + boolean[] init3 = { false, true, false, false, true, true, false }; + int[] init4 = { -2147483648, 2147483647, 0, 1762375167, -604897453, + 1362491587, 1007466498 }; + int[] init5 = { -2147483648, 2147483647, 0, 1494407222, -1696982311, + -940493360, -1777579868 }; + + boolean theReturn; + boolean[] theReturns = init3; + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + theReturn = aDataTruncation.getRead(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetRead + + /* + * Method test for getDataSize + */ + public void testGetDataSize() { + + DataTruncation aDataTruncation; + int[] init1 = { -2147483648, 2147483647, 0, 1146707040, -2020665632, + 1268632617, -1595624039 }; + boolean[] init2 = { false, true, false, true, false, true, true }; + boolean[] init3 = { false, true, false, true, true, false, false }; + int[] init4 = { -2147483648, 2147483647, 0, -367493363, 328996907, + -1581326731, 835022052 }; + int[] init5 = { -2147483648, 2147483647, 0, -886134194, 908213800, + 1123419516, -429606389 }; + + int theReturn; + int[] theReturns = init4; + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + theReturn = aDataTruncation.getDataSize(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetDataSize + + /* + * Method test for getTransferSize + */ + public void testGetTransferSize() { + + DataTruncation aDataTruncation; + int[] init1 = { -2147483648, 2147483647, 0, 78096124, 1719192600, + -1661234694, -1205825753 }; + boolean[] init2 = { false, true, false, false, true, false, true }; + boolean[] init3 = { false, true, false, false, false, false, false }; + int[] init4 = { -2147483648, 2147483647, 0, -493779295, -2042560243, + -217347438, 1357818664 }; + int[] init5 = { -2147483648, 2147483647, 0, -1647009002, -717544563, + -1368171905, -918209633 }; + + int theReturn; + int[] theReturns = init5; + String[] theFinalStates1 = { "01004", "01004", "01004", "01004", + "01004", "01004", "01004" }; + String state2 = "Data truncation"; + String[] theFinalStates2 = { state2, state2, state2, state2, state2, + state2, state2 }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0 }; + int[] theFinalStates4 = init1; + int[] theFinalStates5 = init4; + int[] theFinalStates6 = init5; + boolean[] theFinalStates7 = init2; + boolean[] theFinalStates8 = init3; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aDataTruncation = new DataTruncation(init1[i], init2[i], + init3[i], init4[i], init5[i]); + theReturn = aDataTruncation.getTransferSize(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getSQLState(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getMessage(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getIndex(), theFinalStates4[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getDataSize(), theFinalStates5[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getTransferSize(), theFinalStates6[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getParameter(), theFinalStates7[i]); + assertEquals(i + " Final state mismatch", aDataTruncation + .getRead(), theFinalStates8[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetTransferSize + + /** + * @tests serialization/deserialization compatibility. + */ + public void testSerializationSelf() throws Exception { + DataTruncation object = new DataTruncation(10, true, true, 10, 10); + SerializationTest.verifySelf(object, DATATRUNCATION_COMPARATOR); + } + + /** + * @tests serialization/deserialization compatibility with RI. + */ + public void testSerializationCompatibility() throws Exception { + DataTruncation object = new DataTruncation(10, true, true, 10, 10); + SerializationTest.verifyGolden(this, object, DATATRUNCATION_COMPARATOR); + } + + // comparator for DataTruncation objects + private static final SerializableAssert DATATRUNCATION_COMPARATOR = new SerializableAssert() { + public void assertDeserialized(Serializable initial, + Serializable deserialized) { + + // do common checks for all throwable objects + SerializationTest.THROWABLE_COMPARATOR.assertDeserialized(initial, + deserialized); + + DataTruncation initThr = (DataTruncation) initial; + DataTruncation dserThr = (DataTruncation) deserialized; + + // verify index + assertEquals(initThr.getIndex(), dserThr.getIndex()); + + // verify parameter + assertEquals(initThr.getParameter(), dserThr.getParameter()); + + // verify read + assertEquals(initThr.getRead(), dserThr.getRead()); + + // verify dataSize + assertEquals(initThr.getDataSize(), dserThr.getDataSize()); + + // verify transferSize + assertEquals(initThr.getTransferSize(), dserThr.getTransferSize()); + } + }; + +} // end class DataTruncationTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DatabaseMetaDataTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DatabaseMetaDataTest.java new file mode 100644 index 0000000..c970c70 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DatabaseMetaDataTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class DatabaseMetaDataTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Number> thePublicStatics = new HashMap<String, Number>(); + thePublicStatics.put("sqlStateSQL99", new Integer(2)); + thePublicStatics.put("sqlStateXOpen", new Integer(1)); + thePublicStatics.put("attributeNullableUnknown", new Short((short) 2)); + thePublicStatics.put("attributeNullable", new Short((short) 1)); + thePublicStatics.put("attributeNoNulls", new Short((short) 0)); + thePublicStatics.put("tableIndexOther", new Short((short) 3)); + thePublicStatics.put("tableIndexHashed", new Short((short) 2)); + thePublicStatics.put("tableIndexClustered", new Short((short) 1)); + thePublicStatics.put("tableIndexStatistic", new Short((short) 0)); + thePublicStatics.put("typeSearchable", new Integer(3)); + thePublicStatics.put("typePredBasic", new Integer(2)); + thePublicStatics.put("typePredChar", new Integer(1)); + thePublicStatics.put("typePredNone", new Integer(0)); + thePublicStatics.put("typeNullableUnknown", new Integer(2)); + thePublicStatics.put("typeNullable", new Integer(1)); + thePublicStatics.put("typeNoNulls", new Integer(0)); + thePublicStatics.put("importedKeyNotDeferrable", new Integer(7)); + thePublicStatics.put("importedKeyInitiallyImmediate", new Integer(6)); + thePublicStatics.put("importedKeyInitiallyDeferred", new Integer(5)); + thePublicStatics.put("importedKeySetDefault", new Integer(4)); + thePublicStatics.put("importedKeyNoAction", new Integer(3)); + thePublicStatics.put("importedKeySetNull", new Integer(2)); + thePublicStatics.put("importedKeyRestrict", new Integer(1)); + thePublicStatics.put("importedKeyCascade", new Integer(0)); + thePublicStatics.put("versionColumnPseudo", new Integer(2)); + thePublicStatics.put("versionColumnNotPseudo", new Integer(1)); + thePublicStatics.put("versionColumnUnknown", new Integer(0)); + thePublicStatics.put("bestRowPseudo", new Integer(2)); + thePublicStatics.put("bestRowNotPseudo", new Integer(1)); + thePublicStatics.put("bestRowUnknown", new Integer(0)); + thePublicStatics.put("bestRowSession", new Integer(2)); + thePublicStatics.put("bestRowTransaction", new Integer(1)); + thePublicStatics.put("bestRowTemporary", new Integer(0)); + thePublicStatics.put("columnNullableUnknown", new Integer(2)); + thePublicStatics.put("columnNullable", new Integer(1)); + thePublicStatics.put("columnNoNulls", new Integer(0)); + thePublicStatics.put("procedureNullableUnknown", new Integer(2)); + thePublicStatics.put("procedureNullable", new Integer(1)); + thePublicStatics.put("procedureNoNulls", new Integer(0)); + thePublicStatics.put("procedureColumnResult", new Integer(3)); + thePublicStatics.put("procedureColumnReturn", new Integer(5)); + thePublicStatics.put("procedureColumnOut", new Integer(4)); + thePublicStatics.put("procedureColumnInOut", new Integer(2)); + thePublicStatics.put("procedureColumnIn", new Integer(1)); + thePublicStatics.put("procedureColumnUnknown", new Integer(0)); + thePublicStatics.put("procedureReturnsResult", new Integer(2)); + thePublicStatics.put("procedureNoResult", new Integer(1)); + thePublicStatics.put("procedureResultUnknown", new Integer(0)); + + Class<?> databaseMetaDataClass; + try { + databaseMetaDataClass = Class.forName("java.sql.DatabaseMetaData"); + } catch (ClassNotFoundException e) { + fail("java.sql.DatabaseMetaData class not found!"); + return; + } // end try + + Field[] theFields = databaseMetaDataClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class DatabaseMetaDataTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DateTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DateTest.java new file mode 100644 index 0000000..903b77f --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DateTest.java @@ -0,0 +1,380 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Date; +import java.util.Calendar; +import java.util.TimeZone; + +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.Date class + * + */ +public class DateTest extends TestCase { + + // A calendar object created in the GMT time zone + static Calendar aCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + + // Some interesting millisecond time values + // These millisecond times are all in GMT, effectively + static long TIME_AN_HOUR = 3600000; // 1000 * 60 * 60 ms + + static long TIME_EPOCH = 0; + + static long TIME_NOW = System.currentTimeMillis(); + + static long TIME_NEGATIVE = -3600001; + + static long TIME_TESTDATE1 = getTime(1999, Calendar.DECEMBER, 31, 23, 59, + 59); + + static long TIME_TESTDATE2 = getTime(2010, Calendar.JUNE, 10, 20, 3, 16); + + static long TIME_TESTDATE3 = getTime(1931, Calendar.APRIL, 21, 1, 25, 1); + + static long TIME_LOWERLIMIT = Long.MIN_VALUE; + + static long TIME_UPPERLIMIT = Long.MAX_VALUE; + + // Date strings + static String SQL_DATESTRING1 = "1999-12-31"; + + static String SQL_DATESTRING2 = "2010-06-10"; + + static String SQL_DATESTRING3 = "1931-04-21"; + + static String SQL_EPOCHSTRING = "1970-01-01"; + + static String SQL_DATEDAY1 = "1970-01-02"; + + static String SQL_NEGATIVE = "1969-12-31"; + + static long[] TIME_ARRAY = new long[] { TIME_TESTDATE1, TIME_TESTDATE2, + TIME_TESTDATE3, TIME_NEGATIVE, TIME_EPOCH }; + + // Date string array for London (GMT) + static String[] SQL_DATEARRAY = new String[] { SQL_DATESTRING1, + SQL_DATESTRING2, SQL_DATESTRING3, SQL_NEGATIVE, SQL_EPOCHSTRING }; + + // Date string array for New York - sometimes a day earlier than London + static String[] SQL_NYARRAY = new String[] { "1999-12-31", "2010-06-10", + "1931-04-20", "1969-12-31", "1969-12-31" }; + + // Date string for Tokyo + static String[] SQL_JAPANARRAY = new String[] { "2000-01-01", "2010-06-11", + "1931-04-21", "1970-01-01", "1970-01-01" }; + + static String[][] SQL_TZ_DATEARRAYS = new String[][] { SQL_DATEARRAY, + SQL_NYARRAY, SQL_JAPANARRAY }; + + // Timezones + static String TZ_LONDON = "Europe/London"; // Note: != GMT + + static String TZ_PACIFIC = "America/Los_Angeles"; // GNT - 8 + + static String TZ_JAPAN = "Asia/Tokyo"; // GMT + 9 + + static String[] TIMEZONES = { TZ_LONDON, TZ_PACIFIC, TZ_JAPAN }; + + /* + * Helper method to create a long milliseconds time from a supplied date and + * time + */ + static private long getTime(int year, int month, int date, int hour, + int minute, int second) { + aCal.set(year, month, date, hour, minute, second); + return aCal.getTimeInMillis(); + } // end method getTime( int, int, int, int, int, int ) + + /* + * Test of the Date(int, int, int) constructor - now deprecated but still + * functioning + */ + @SuppressWarnings("deprecation") + public void testDateintintint() { + + int init1[] = { 99, 8099, 9000, 99999, 99, 99, -1, -100 }; + int init2[] = { 11, 0, 0, 0, 999, 0, 0, -111 }; + int init3[] = { 31, 0, 0, 0, 0, 999, 0, -999 }; + + for (int i = 0; i < init1.length; i++) { + Date theDate = new Date(init1[i], init2[i], init3[i]); + assertNotNull(theDate); + } // end for + + } // end method testDateintintint + + /* + * Test of the Date( long ) constructor + */ + public void testDatelong() { + + long init1[] = { TIME_TESTDATE1, TIME_TESTDATE2, TIME_TESTDATE3, + TIME_NEGATIVE, TIME_LOWERLIMIT, TIME_UPPERLIMIT, TIME_EPOCH, + TIME_NOW }; + + for (long element : init1) { + Date theDate = new Date(element); + assertNotNull(theDate); + } // end for + + } // end method testDatelong + + /* + * Test of the (deprecated) int Date.getHours() method - which always throws + * an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testGetHours() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.getHours(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + } // end method testGetHours() + + /* + * Test of the (deprecated) int Date.getMinutes() method - which always + * throws an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testGetMinutes() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.getMinutes(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + } // end method testGetMinutes() + + /* + * Test of the (deprecated) int Date.getSeconds() method - which always + * throws an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testGetSeconds() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.getSeconds(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + } // end method testGetSeconds() + + /* + * Test of the (deprecated) Date.setHours( int ) method - which always + * throws an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testSetHours() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.setHours(22); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + } // end method testSetHours( int ) + + /* + * Test of the (deprecated) Date.setMinutes( int ) method - which always + * throws an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testSetMinutes() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.setMinutes(54); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + + } // end method testSetMinutes( int ) + + /* + * Test of the (deprecated) Date.setSeconds( int ) method - which always + * throws an IllegalArgumentException + */ + @SuppressWarnings("deprecation") + public void testSetSeconds() { + Date theDate = new Date(TIME_TESTDATE1); + try { + theDate.setSeconds(36); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException ie) { + //expected + } // end try + } // end method testSetSeconds( int ) + + /* + * Test of the String Date.toString() method This method is sensitive to the + * time zone setting and this test sets the time zone before calling the + * toString() method. + */ + public void testToString() { + // This test is set up for GMT time zone, so need to set the time zone + // to GMT first + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + for (int i = 0; i < TIME_ARRAY.length; i++) { + Date theDate = new Date(TIME_ARRAY[i]); + assertEquals(SQL_DATEARRAY[i], theDate.toString()); + } // end for + + } // end method testToString() + + /* + * Test of the void setTime(int) method This does depend on the Time Zone + * settings and sets up the time zone to one of a group of specific time + * zones and tests the method using each of these time zones in turn. + */ + public void testSetTimelong() { + + // Loop over the array of test timezones + for (int i = 0; i < TIMEZONES.length; i++) { + testSetTimelong(TIMEZONES[i], SQL_TZ_DATEARRAYS[i]); + } // end for + + } // end method testSetTimelong() + + /* + * Internal method for testing Date.setTime with a specific time zone + */ + private void testSetTimelong(String timeZoneName, String[] dateArray) { + + if (timeZoneName != null) { + TimeZone.setDefault(TimeZone.getTimeZone(timeZoneName)); + } // end if + + Date theDate = new Date(TIME_TESTDATE1); + + // Loop over the array of test times & dates + for (int i = 0; i < dateArray.length; i++) { + theDate.setTime(TIME_ARRAY[i]); + assertEquals(dateArray[i], theDate.toString()); + } // end for + + } // end method testSetTimelong() + + /* + * Test of the Date.valueOf( String ) method This test is not dependent on + * the default Time Zone setting + */ + public void testValueOf() { + String SQL_NOTVALID1 = "ABCDEF"; // Invalid date string + String SQL_NOTVALID2 = "12321.43.56"; // Invalid date string + String SQL_NOTVALID3 = null; // Invalid date string + String[] SQL_INVALIDARRAY = { SQL_NOTVALID1, SQL_NOTVALID2, + SQL_NOTVALID3 }; + + Date theDate; + + for (String element : SQL_DATEARRAY) { + theDate = Date.valueOf(element); + assertEquals(element, theDate.toString()); + } // end for + + for (String element : SQL_INVALIDARRAY) { + try { + theDate = Date.valueOf(element); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end for + + } // end method testValueOf() + + /** + * @tests java.sql.Date#valueOf(String ) + */ + public void test_valueOf_IllegalArgumentException() { + try{ + Date.valueOf("1996-10-07-01"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + + try{ + Date.valueOf("-10-07-01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("--01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("1991--"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("-01-"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("-10-w2-01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("07-w2-"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Date.valueOf("1997-w2-w2"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + + try{ + Date.valueOf("1996--01"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + } + +} // end class DateTest + + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverManagerTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverManagerTest.java new file mode 100644 index 0000000..73b415b --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverManagerTest.java @@ -0,0 +1,582 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.security.Permission; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.SQLPermission; +import java.util.Enumeration; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.DriverManager class + * + */ +public class DriverManagerTest extends TestCase { + + // Set of driver names to use + static final String DRIVER1 = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver1"; + + static final String DRIVER2 = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver2"; + + static final String DRIVER3 = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver3"; + + static final String DRIVER4 = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver4"; + + static final String DRIVER5 = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver5"; + + static final String INVALIDDRIVER1 = "abc.klm.Foo"; + + static String[] driverNames = { DRIVER1, DRIVER2 }; + + static int numberLoaded; + + static String baseURL1 = "jdbc:mikes1"; + + static String baseURL4 = "jdbc:mikes4"; + + static final String JDBC_PROPERTY = "jdbc.drivers"; + + static TestHelper_ClassLoader testClassLoader = new TestHelper_ClassLoader(); + + // Static initializer to load the drivers so that they are available to all + // the + // test methods as needed. + @Override + public void setUp() { + numberLoaded = loadDrivers(); + } // end setUp() + + /** + * Test for the method DriverManager.deregisterDriver + * @throws SQLException + */ + public void testDeregisterDriver() throws SQLException { + // First get one of the drivers loaded by the test + Driver aDriver; + aDriver = DriverManager.getDriver(baseURL4); + + // Deregister this driver + DriverManager.deregisterDriver(aDriver); + + assertFalse("testDeregisterDriver: Driver was not deregistered.", + isDriverLoaded(aDriver)); + + // Re-register this driver (so subsequent tests have it available) + DriverManager.registerDriver(aDriver); + assertTrue("testDeregisterDriver: Driver did not reload.", + isDriverLoaded(aDriver)); + + // Test deregistering a null driver + DriverManager.deregisterDriver(null); + + // Test deregistering a driver which was not loaded by this test's + // classloader + // TODO - need to load a driver with a different classloader!! + aDriver = DriverManager.getDriver(baseURL1); + + try { + Class<?> driverClass = Class.forName( + "org.apache.harmony.sql.tests.java.sql.TestHelper_DriverManager", true, + testClassLoader); + + // Give the Helper class one of our drivers.... + Class<?>[] methodClasses = { Class.forName("java.sql.Driver") }; + Method theMethod = driverClass.getDeclaredMethod("setDriver", + methodClasses); + Object[] args = { aDriver }; + theMethod.invoke(null, args); + } catch (Exception e) { + System.out + .println("testDeregisterDriver: Got exception allocating TestHelper"); + e.printStackTrace(); + return; + } // end try + + // Check that the driver was not deregistered + assertTrue( + "testDeregisterDriver: Driver was incorrectly deregistered.", + DriverManagerTest.isDriverLoaded(aDriver)); + + } // end method testDeregisterDriver() + + static void printClassLoader(Object theObject) { + Class<? extends Object> theClass = theObject.getClass(); + ClassLoader theClassLoader = theClass.getClassLoader(); + System.out.println("ClassLoader is: " + theClassLoader.toString() + + " for object: " + theObject.toString()); + } // end method printClassLoader( Object ) + + static boolean isDriverLoaded(Driver theDriver) { + Enumeration<?> driverList = DriverManager.getDrivers(); + while (driverList.hasMoreElements()) { + if ((Driver) driverList.nextElement() == theDriver) { + return true; + } + } // end while + return false; + } // end method isDriverLoaded( Driver ) + + /* + * Class under test for Connection getConnection(String) + */ + // valid connection - data1 does not require a user and password... + static String validConnectionURL = "jdbc:mikes1:data1"; + + // invalid connection - data2 requires a user & password + static String invalidConnectionURL1 = "jdbc:mikes1:data2"; + + // invalid connection - URL is gibberish + static String invalidConnectionURL2 = "xyz1:abc3:456q"; + + // invalid connection - URL is null + static String invalidConnectionURL3 = null; + + static String[] invalidConnectionURLs = { invalidConnectionURL2, + invalidConnectionURL3 }; + + public void testGetConnectionString() throws SQLException { + Connection theConnection = null; + // validConnection - no user & password required + theConnection = DriverManager.getConnection(validConnectionURL); + assertNotNull(theConnection); + assertNotNull(DriverManager.getConnection(invalidConnectionURL1)); + + for (String element : invalidConnectionURLs) { + try { + theConnection = DriverManager + .getConnection(element); + fail("Should throw SQLException"); + } catch (SQLException e) { + //expected + } // end try + } // end for + } // end method testGetConnectionString() + + /** + * @tests java.sql.DriverManager#getConnection(String, Properties) + */ + public void test_getConnection_LStringLProperties() { + try { + DriverManager.getConnection("fff", //$NON-NLS-1$ + new Properties()); + fail("Should throw SQLException."); + } catch (SQLException e) { + assertEquals("08001", e.getSQLState()); //$NON-NLS-1$ + } + + try { + DriverManager.getConnection(null, + new Properties()); + fail("Should throw SQLException."); + } catch (SQLException e) { + assertEquals("08001", e.getSQLState()); //$NON-NLS-1$ + } + } + + /* + * Class under test for Connection getConnection(String, Properties) + */ + public void testGetConnectionStringProperties() throws SQLException { + String validURL1 = "jdbc:mikes1:data2"; + String validuser1 = "theuser"; + String validpassword1 = "thepassword"; + String invalidURL1 = "xyz:abc1:foo"; + String invalidURL2 = "jdbc:mikes1:crazyone"; + String invalidURL3 = ""; + String invaliduser1 = "jonny nouser"; + String invalidpassword1 = "whizz"; + Properties nullProps = null; + Properties validProps = new Properties(); + validProps.setProperty("user", validuser1); + validProps.setProperty("password", validpassword1); + Properties invalidProps1 = new Properties(); + invalidProps1.setProperty("user", invaliduser1); + invalidProps1.setProperty("password", invalidpassword1); + String[] invalidURLs = { null, invalidURL1, + invalidURL2, invalidURL3 }; + Properties[] invalidProps = { nullProps, invalidProps1}; + + + + Connection theConnection = null; + // validConnection - user & password required + theConnection = DriverManager.getConnection(validURL1, validProps); + assertNotNull(theConnection); + + // invalid Connections + for (int i = 0; i < invalidURLs.length; i++) { + theConnection = null; + try { + theConnection = DriverManager.getConnection(invalidURLs[i], + validProps); + fail("Should throw SQLException"); + } catch (SQLException e) { + //expected + } // end try + } // end for + for (Properties invalidProp : invalidProps) { + assertNotNull(DriverManager.getConnection(validURL1, invalidProp)); + } + } // end method testGetConnectionStringProperties() + + /* + * Class under test for Connection getConnection(String, String, String) + */ + public void testGetConnectionStringStringString() throws SQLException { + String validURL1 = "jdbc:mikes1:data2"; + String validuser1 = "theuser"; + String validpassword1 = "thepassword"; + String invalidURL1 = "xyz:abc1:foo"; + String invaliduser1 = "jonny nouser"; + String invalidpassword1 = "whizz"; + String[] invalid1 = { null, validuser1, validpassword1 }; + String[] invalid2 = { validURL1, null, validpassword1 }; + String[] invalid3 = { validURL1, validuser1, null }; + String[] invalid4 = { invalidURL1, validuser1, validpassword1 }; + String[] invalid5 = { validURL1, invaliduser1, invalidpassword1 }; + String[] invalid6 = { validURL1, validuser1, invalidpassword1 }; + String[][] invalids1 = { invalid1, invalid4}; + String[][] invalids2 = {invalid2, invalid3, invalid5, invalid6 }; + + Connection theConnection = null; + // validConnection - user & password required + theConnection = DriverManager.getConnection(validURL1, validuser1, + validpassword1); + assertNotNull(theConnection); + for (String[] theData : invalids1) { + theConnection = null; + try { + theConnection = DriverManager.getConnection(theData[0], + theData[1], theData[2]); + fail("Should throw SQLException."); + } catch (SQLException e) { + //expected + } // end try + } // end for + for (String[] theData : invalids2) { + assertNotNull(DriverManager.getConnection(theData[0], theData[1], + theData[2])); + } + } // end method testGetConnectionStringStringString() + + static String validURL1 = "jdbc:mikes1"; + + static String validURL2 = "jdbc:mikes2"; + + static String invalidURL1 = "xyz:acb"; + + static String invalidURL2 = null; + + static String[] validURLs = { validURL1, validURL2 }; + + static String[] invalidURLs = { invalidURL1, invalidURL2 }; + + static String exceptionMsg1 = "No suitable driver"; + + public void testGetDriver() throws SQLException { + for (String element : validURLs) { + Driver validDriver = DriverManager.getDriver(element); + assertNotNull(validDriver); + } // end for + + for (String element : invalidURLs) { + try { + DriverManager.getDriver(element); + fail("Should throw SQLException"); + } catch (SQLException e) { + assertEquals("08001", e.getSQLState()); + assertEquals(exceptionMsg1, e.getMessage()); + } // end try + } // end for + + } // end method testGetDriver() + + public void testGetDrivers() { + // Load a driver manager + Enumeration<Driver> driverList = DriverManager.getDrivers(); + int i = 0; + while (driverList.hasMoreElements()) { + Driver theDriver = driverList.nextElement(); + assertNotNull(theDriver); + i++; + } // end while + + // Check that all the drivers are in the list... + assertEquals("testGetDrivers: Don't see all the loaded drivers - ", i, + numberLoaded); + } // end method testGetDrivers() + + static int timeout1 = 25; + + public void testGetLoginTimeout() { + DriverManager.setLoginTimeout(timeout1); + assertEquals(timeout1, DriverManager.getLoginTimeout()); + } // end method testGetLoginTimeout() + + @SuppressWarnings("deprecation") + public void testGetLogStream() { + assertNull(DriverManager.getLogStream()); + + DriverManager.setLogStream(testPrintStream); + assertTrue(DriverManager.getLogStream() == testPrintStream); + + DriverManager.setLogStream(null); + } // end method testGetLogStream() + + public void testGetLogWriter() { + assertNull(DriverManager.getLogWriter()); + + DriverManager.setLogWriter(testPrintWriter); + + assertTrue(DriverManager.getLogWriter() == testPrintWriter); + + DriverManager.setLogWriter(null); + } // end method testGetLogWriter() + + static String testMessage = "DriverManagerTest: test message for print stream"; + + @SuppressWarnings("deprecation") + public void testPrintln() { + // System.out.println("testPrintln"); + DriverManager.println(testMessage); + + DriverManager.setLogWriter(testPrintWriter); + DriverManager.println(testMessage); + + String theOutput = outputStream.toString(); + // System.out.println("testPrintln: output= " + theOutput ); + assertTrue(theOutput.startsWith(testMessage)); + + DriverManager.setLogWriter(null); + + DriverManager.setLogStream(testPrintStream); + DriverManager.println(testMessage); + + theOutput = outputStream2.toString(); + // System.out.println("testPrintln: output= " + theOutput ); + assertTrue(theOutput.startsWith(testMessage)); + + DriverManager.setLogStream(null); + } // end method testPrintln() + + public void testRegisterDriver() throws ClassNotFoundException, + SQLException, IllegalAccessException, InstantiationException { + String EXTRA_DRIVER_NAME = "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver3"; + + try { + DriverManager.registerDriver(null); + fail("Should throw NullPointerException."); + } catch (NullPointerException e) { + // expected + } // end try + + Driver theDriver = null; + // Load another Driver that isn't in the basic set + Class<?> driverClass = Class.forName(EXTRA_DRIVER_NAME); + theDriver = (Driver) driverClass.newInstance(); + DriverManager.registerDriver(theDriver); + + assertTrue("testRegisterDriver: driver not in loaded set", + isDriverLoaded(theDriver)); + + } // end testRegisterDriver() + + static int validTimeout1 = 15; + + static int validTimeout2 = 0; + + static int[] validTimeouts = { validTimeout1, validTimeout2 }; + + static int invalidTimeout1 = -10; + + public void testSetLoginTimeout() { + for (int element : validTimeouts) { + DriverManager.setLoginTimeout(element); + + assertEquals(element, DriverManager.getLoginTimeout()); + } // end for + // Invalid timeouts + DriverManager.setLoginTimeout(invalidTimeout1); + assertEquals(invalidTimeout1, DriverManager.getLoginTimeout()); + } // end testSetLoginTimeout() + + static ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream(); + + static PrintStream testPrintStream = new PrintStream(outputStream2); + + @SuppressWarnings("deprecation") + public void testSetLogStream() { + // System.out.println("testSetLogStream"); + DriverManager.setLogStream(testPrintStream); + + assertSame(testPrintStream, DriverManager.getLogStream()); + + DriverManager.setLogStream(null); + + assertNull(DriverManager.getLogStream()); + + // Now let's deal with the case where there is a SecurityManager in + // place + TestSecurityManager theSecManager = new TestSecurityManager(); + System.setSecurityManager(theSecManager); + + theSecManager.setLogAccess(false); + + try { + DriverManager.setLogStream(testPrintStream); + fail("Should throw SecurityException."); + } catch (SecurityException s) { + //expected + } + + theSecManager.setLogAccess(true); + + DriverManager.setLogStream(testPrintStream); + + System.setSecurityManager(null); + } // end method testSetLogStream() + + static ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + static PrintWriter testPrintWriter = new PrintWriter(outputStream); + + /** + * Test for the setLogWriter method + */ + public void testSetLogWriter() { + // System.out.println("testSetLogWriter"); + DriverManager.setLogWriter(testPrintWriter); + + assertSame(testPrintWriter, DriverManager.getLogWriter()); + + DriverManager.setLogWriter(null); + + assertNull("testDriverManager: Log writer not null:", DriverManager + .getLogWriter()); + + // Now let's deal with the case where there is a SecurityManager in + // place + TestSecurityManager theSecManager = new TestSecurityManager(); + System.setSecurityManager(theSecManager); + + theSecManager.setLogAccess(false); + + try { + DriverManager.setLogWriter(testPrintWriter); + fail("Should throw SecurityException."); + } catch (SecurityException s) { + //expected + } + + theSecManager.setLogAccess(true); + DriverManager.setLogWriter(testPrintWriter); + + System.setSecurityManager(null); + } // end method testSetLogWriter() + + /* + * Method which loads a set of JDBC drivers ready for use by the various + * tests @return the number of drivers loaded + */ + static boolean driversLoaded = false; + + private static int loadDrivers() { + if (driversLoaded) { + return numberLoaded; + } + /* + * First define a value for the System property "jdbc.drivers" - before + * the DriverManager class is loaded - this property defines a set of + * drivers which the DriverManager will load during its initialization + * and which will be loaded on the System ClassLoader - unlike the ones + * loaded later by this method which are loaded on the Application + * ClassLoader. + */ + int numberLoaded = 0; + String theSystemDrivers = DRIVER4 + ":" + DRIVER5 + ":" + + INVALIDDRIVER1; + System.setProperty(JDBC_PROPERTY, theSystemDrivers); + numberLoaded += 2; + + for (String element : driverNames) { + try { + Class<?> driverClass = Class.forName(element); + assertNotNull(driverClass); + // System.out.println("Loaded driver - classloader = " + + // driverClass.getClassLoader()); + numberLoaded++; + } catch (ClassNotFoundException e) { + System.out.println("DriverManagerTest: failed to load Driver: " + + element); + } // end try + } // end for + /* + * System.out.println("DriverManagerTest: number of drivers loaded: " + + * numberLoaded); + */ + driversLoaded = true; + return numberLoaded; + } // end method loadDrivers() + + class TestSecurityManager extends SecurityManager { + + boolean logAccess = true; + + SQLPermission sqlPermission = new SQLPermission("setLog"); + + RuntimePermission setManagerPermission = new RuntimePermission( + "setSecurityManager"); + + TestSecurityManager() { + super(); + } // end method TestSecurityManager() + + void setLogAccess(boolean allow) { + logAccess = allow; + } // end method setLogAccess( boolean ) + + @Override + public void checkPermission(Permission thePermission) { + if (thePermission.equals(sqlPermission)) { + if (!logAccess) { + throw new SecurityException("Cannot set the sql Log Writer"); + } // end if + return; + } // end if + + if (thePermission.equals(setManagerPermission)) { + return; + } // end if + // super.checkPermission( thePermission ); + } // end method checkPermission( Permission ) + + } // end class TestSecurityManager + +} // end class DriverManagerTest + + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverPropertyInfoTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverPropertyInfoTest.java new file mode 100644 index 0000000..ec38988 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/DriverPropertyInfoTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.DriverPropertyInfo; +import java.util.Arrays; + +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.DriverPropertyInfo class + * + */ + +public class DriverPropertyInfoTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + } // end method testPublicStatics + + /* + * Constructor test + */ + public void testDriverPropertyInfoStringString() { + + DriverPropertyInfo aDriverPropertyInfo = new DriverPropertyInfo( + validName, validValue); + + assertNotNull(aDriverPropertyInfo); + + aDriverPropertyInfo = new DriverPropertyInfo(null, null); + + } // end method testDriverPropertyInfoStringString + + /* + * Public fields test + */ + static String validName = "testname"; + + static String validValue = "testvalue"; + + static String[] updateChoices = { "Choice1", "Choice2", "Choice3" }; + + static String updateValue = "updateValue"; + + static boolean updateRequired = true; + + static String updateDescription = "update description"; + + static String updateName = "updateName"; + + public void testPublicFields() { + + // Constructor here... + DriverPropertyInfo aDriverPropertyInfo = new DriverPropertyInfo( + validName, validValue); + + assertTrue(Arrays.equals(testChoices, aDriverPropertyInfo.choices)); + assertEquals(testValue, aDriverPropertyInfo.value); + assertEquals(testRequired, aDriverPropertyInfo.required); + assertEquals(testDescription, aDriverPropertyInfo.description); + assertEquals(testName, aDriverPropertyInfo.name); + + aDriverPropertyInfo.choices = updateChoices; + aDriverPropertyInfo.value = updateValue; + aDriverPropertyInfo.required = updateRequired; + aDriverPropertyInfo.description = updateDescription; + aDriverPropertyInfo.name = updateName; + + assertTrue(Arrays.equals(updateChoices, aDriverPropertyInfo.choices)); + assertEquals(updateValue, aDriverPropertyInfo.value); + assertEquals(updateRequired, aDriverPropertyInfo.required); + assertEquals(updateDescription, aDriverPropertyInfo.description); + assertEquals(updateName, aDriverPropertyInfo.name); + + } // end method testPublicFields + + // Default values... + static String[] testChoices = null; + + static java.lang.String testValue = validValue; + + static boolean testRequired = false; + + static java.lang.String testDescription = null; + + static java.lang.String testName = validName; + +} // end class DriverPropertyInfoTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ParameterMetaDataTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ParameterMetaDataTest.java new file mode 100644 index 0000000..d3e000d --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ParameterMetaDataTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class ParameterMetaDataTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("parameterModeOut", new Integer(4)); + thePublicStatics.put("parameterModeInOut", new Integer(2)); + thePublicStatics.put("parameterModeIn", new Integer(1)); + thePublicStatics.put("parameterModeUnknown", new Integer(0)); + thePublicStatics.put("parameterNullableUnknown", new Integer(2)); + thePublicStatics.put("parameterNullable", new Integer(1)); + thePublicStatics.put("parameterNoNulls", new Integer(0)); + + /* + * System.out.println( "parameterModeOut: " + + * ParameterMetaData.parameterModeOut ); System.out.println( + * "parameterModeInOut: " + ParameterMetaData.parameterModeInOut ); + * System.out.println( "parameterModeIn: " + + * ParameterMetaData.parameterModeIn ); System.out.println( + * "parameterModeUnknown: " + ParameterMetaData.parameterModeUnknown ); + * System.out.println( "parameterNullableUnknown: " + + * ParameterMetaData.parameterNullableUnknown ); System.out.println( + * "parameterNullable: " + ParameterMetaData.parameterNullable ); + * System.out.println( "parameterNoNulls: " + + * ParameterMetaData.parameterNoNulls ); + */ + + Class<?> parameterMetaDataClass; + try { + parameterMetaDataClass = Class + .forName("java.sql.ParameterMetaData"); + } catch (ClassNotFoundException e) { + fail("java.sql.ParameterMetaData class not found!"); + return; + } // end try + + Field[] theFields = parameterMetaDataClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class ParameterMetaDataTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetMetaDataTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetMetaDataTest.java new file mode 100644 index 0000000..07a25c2 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetMetaDataTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class ResultSetMetaDataTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("columnNullableUnknown", new Integer(2)); + thePublicStatics.put("columnNullable", new Integer(1)); + thePublicStatics.put("columnNoNulls", new Integer(0)); + + /* + * System.out.println( "columnNullableUnknown: " + + * ResultSetMetaData.columnNullableUnknown ); System.out.println( + * "columnNullable: " + ResultSetMetaData.columnNullable ); + * System.out.println( "columnNoNulls: " + + * ResultSetMetaData.columnNoNulls ); + */ + + Class<?> resultSetMetaDataClass; + try { + resultSetMetaDataClass = Class + .forName("java.sql.ResultSetMetaData"); + } catch (ClassNotFoundException e) { + fail("java.sql.ResultSetMetaData class not found!"); + return; + } // end try + + Field[] theFields = resultSetMetaDataClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class ResultSetMetaDataTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetTest.java new file mode 100644 index 0000000..26e61fe --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/ResultSetTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class ResultSetTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("CLOSE_CURSORS_AT_COMMIT", + new java.lang.Integer(2)); + thePublicStatics.put("HOLD_CURSORS_OVER_COMMIT", new java.lang.Integer( + 1)); + thePublicStatics.put("CONCUR_UPDATABLE", new java.lang.Integer(1008)); + thePublicStatics.put("CONCUR_READ_ONLY", new java.lang.Integer(1007)); + thePublicStatics.put("TYPE_SCROLL_SENSITIVE", new java.lang.Integer( + 1005)); + thePublicStatics.put("TYPE_SCROLL_INSENSITIVE", new java.lang.Integer( + 1004)); + thePublicStatics.put("TYPE_FORWARD_ONLY", new java.lang.Integer(1003)); + thePublicStatics.put("FETCH_UNKNOWN", new java.lang.Integer(1002)); + thePublicStatics.put("FETCH_REVERSE", new java.lang.Integer(1001)); + thePublicStatics.put("FETCH_FORWARD", new java.lang.Integer(1000)); + + /* + * System.out.println( "CLOSE_CURSORS_AT_COMMIT: " + + * ResultSet.CLOSE_CURSORS_AT_COMMIT ); System.out.println( + * "HOLD_CURSORS_OVER_COMMIT: " + ResultSet.HOLD_CURSORS_OVER_COMMIT ); + * System.out.println( "CONCUR_UPDATABLE: " + ResultSet.CONCUR_UPDATABLE ); + * System.out.println( "CONCUR_READ_ONLY: " + ResultSet.CONCUR_READ_ONLY ); + * System.out.println( "TYPE_SCROLL_SENSITIVE: " + + * ResultSet.TYPE_SCROLL_SENSITIVE ); System.out.println( + * "TYPE_SCROLL_INSENSITIVE: " + ResultSet.TYPE_SCROLL_INSENSITIVE ); + * System.out.println( "TYPE_FORWARD_ONLY: " + + * ResultSet.TYPE_FORWARD_ONLY ); System.out.println( "FETCH_UNKNOWN: " + + * ResultSet.FETCH_UNKNOWN ); System.out.println( "FETCH_REVERSE: " + + * ResultSet.FETCH_REVERSE ); System.out.println( "FETCH_FORWARD: " + + * ResultSet.FETCH_FORWARD ); + */ + + Class<?> resultSetClass; + try { + resultSetClass = Class.forName("java.sql.ResultSet"); + } catch (ClassNotFoundException e) { + fail("java.sql.ResultSet class not found!"); + return; + } // end try + + Field[] theFields = resultSetClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class ResultSetTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.java new file mode 100644 index 0000000..bb73343 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.java @@ -0,0 +1,541 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.sql.SQLException; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; + +import junit.framework.Assert; +import junit.framework.TestCase; + +public class SQLExceptionTest extends TestCase { + + static long theFixedSUID = 2135244094396331484L; + + /* + * SUID test + */ + public void testSUID() { + + try { + Class<?> theClass = Class.forName("java.sql.SQLException"); + Field theField = theClass.getDeclaredField("serialVersionUID"); + theField.setAccessible(true); + long theSUID = theField.getLong(null); + assertEquals("SUID mismatch: ", theFixedSUID, theSUID); + } catch (Exception e) { + System.out.println("SUID check got exception: " + e.getMessage()); + // assertTrue("Exception while testing SUID ", false ); + } // end catch + + } // end method testSUID + + /* + * ConstructorTest + */ + public void testSQLExceptionStringStringint() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", "1", "a", + null, "", "\u0000", "a", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "a", + "&valid*", "a", "a", "a", null, "", "\u0000" }; + int[] init3 = { -2147483648, 2147483647, 0, 48429456, 1770127344, + 1047282235, -545472907, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648 }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLException[] theFinalStates4 = { null, null, null, null, null, null, + null, null, null, null, null, null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null, null, null }; + + SQLException aSQLException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i], init3[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLExceptionStringStringint + + /* + * ConstructorTest + */ + public void testSQLExceptionStringString() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, "", + "\u0000", "a", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "a", "a", + "a", null, "", "\u0000" }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 }; + SQLException[] theFinalStates4 = { null, null, null, null, null, null, + null, null, null, null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null }; + + SQLException aSQLException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLExceptionStringString + + /* + * ConstructorTest + */ + public void testSQLExceptionString() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, + "", "\u0000" }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = { null, null, null, null, null, null, null, + null }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, + 0, 0, 0 }; + SQLException[] theFinalStates4 = { null, null, null, null, null, null, + null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null }; + + SQLException aSQLException; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLExceptionString + + /* + * ConstructorTest + */ + public void testSQLException() { + + String[] theFinalStates1 = { null }; + String[] theFinalStates2 = { null }; + int[] theFinalStates3 = { 0 }; + SQLException[] theFinalStates4 = { null }; + + Exception[] theExceptions = { null }; + + SQLException aSQLException; + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLException + + /* + * Method test for getErrorCode + */ + public void testGetErrorCode() { + + SQLException aSQLException; + String[] init1 = { "a", "1", "valid1", "----", null, "&valid*", "1" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", null, "a" }; + int[] init3 = { -2147483648, 2147483647, 0, 48429456, 1770127344, + 1047282235, -545472907 }; + + int theReturn; + int[] theReturns = init3; + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLException[] theFinalStates4 = { null, null, null, null, null, null, + null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i], init3[i]); + theReturn = aSQLException.getErrorCode(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetErrorCode + + /* + * Method test for getNextException + */ + public void testGetNextException() { + + SQLException aSQLException; + String[] init1 = { "a", "1", "valid1", "----", null, "&valid*", "1" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", null, "a" }; + int[] init3 = { -2147483648, 2147483647, 0, 48429456, 1770127344, + 1047282235, -545472907 }; + SQLException[] init4 = { new SQLException(), null, new SQLException(), + new SQLException(), new SQLException(), null, + new SQLException() }; + + SQLException theReturn; + SQLException[] theReturns = init4; + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLException[] theFinalStates4 = init4; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i], init3[i]); + aSQLException.setNextException(init4[i]); + theReturn = aSQLException.getNextException(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetNextException + + /* + * Method test for getSQLState + */ + public void testGetSQLState() { + + SQLException aSQLException; + String[] init1 = { "a", "1", "valid1", "----", null, "&valid*", "1" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", null, "a" }; + int[] init3 = { -2147483648, 2147483647, 0, 48429456, 1770127344, + 1047282235, -545472907 }; + + String theReturn; + String[] theReturns = init2; + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLException[] theFinalStates4 = { null, null, null, null, null, null, + null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i], init3[i]); + theReturn = aSQLException.getSQLState(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetSQLState + + /* + * Method test for setNextException + */ + public void testSetNextExceptionSQLException() { + + SQLException[] parm1 = { new SQLException(), null, new SQLException(), + new SQLException(), new SQLException(), null, + new SQLException() }; + + SQLException aSQLException; + + String[] init1 = { "a", "1", "valid1", "----", null, "&valid*", "1" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", null, "a" }; + int[] init3 = { -2147483648, 2147483647, 0, 48429456, 1770127344, + 1047282235, -545472907 }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLException[] theFinalStates4 = parm1; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null }; + + int loopCount = parm1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLException = new SQLException(init1[i], init2[i], init3[i]); + aSQLException.setNextException(parm1[i]); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + " Final state mismatch", aSQLException + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLException + .getNextException(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSetNextExceptionSQLException + + /** + * @tests serialization/deserialization compatibility. + */ + public void testSerializationSelf() throws Exception { + SQLException object = new SQLException(); + SerializationTest.verifySelf(object, SQLEXCEPTION_COMPARATOR); + } + + /** + * @tests serialization/deserialization compatibility with RI. + */ + public void testSerializationCompatibility() throws Exception { + + SQLException nextSQLException = new SQLException("nextReason", + "nextSQLState", 33); + + int vendorCode = 10; + SQLException object = new SQLException("reason", "SQLState", vendorCode); + + object.setNextException(nextSQLException); + + SerializationTest.verifyGolden(this, object, SQLEXCEPTION_COMPARATOR); + } + + // comparator for SQLException objects + private static final SerializableAssert SQLEXCEPTION_COMPARATOR = new SerializableAssert() { + public void assertDeserialized(Serializable initial, + Serializable deserialized) { + + // do common checks for all throwable objects + SerializationTest.THROWABLE_COMPARATOR.assertDeserialized(initial, + deserialized); + + SQLException initThr = (SQLException) initial; + SQLException dserThr = (SQLException) deserialized; + + // verify SQLState + Assert.assertEquals("SQLState", initThr.getSQLState(), dserThr + .getSQLState()); + + // verify vendorCode + Assert.assertEquals("vendorCode", initThr.getErrorCode(), dserThr + .getErrorCode()); + + // verify next + if (initThr.getNextException() == null) { + assertNull(dserThr.getNextException()); + } else { + // use the same comparator + SQLEXCEPTION_COMPARATOR.assertDeserialized(initThr + .getNextException(), dserThr.getNextException()); + } + } + }; + + /** + * @tests java.sql.SQLException#setNextException(java.sql.SQLException) + */ + public void test_setNextException_LSQLException() { + SQLException se1 = new SQLException("reason" , "SQLState" , 1); + SQLException se2 = new SQLException("reason" , "SQLState" , 2); + SQLException se3 = new SQLException("reason" , "SQLState" , 3); + SQLException se4 = new SQLException("reason" , "SQLState" , 4); + + se1.setNextException(se2); + assertSame(se2, se1.getNextException()); + + se1.setNextException(se3); + assertSame(se2, se1.getNextException()); + assertSame(se3, se2.getNextException()); + assertNull(se3.getNextException()); + + se3.setNextException(null); + assertNull(se3.getNextException()); + + se3.setNextException(se4); + assertSame(se4, se3.getNextException()); + } + +} // end class SQLExceptionTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLPermissionTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLPermissionTest.java new file mode 100644 index 0000000..0cf1d45 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLPermissionTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.SQLPermission; + +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.SQLPermission class + * + * Note that the SQLPermission class only defines 2 constructors and all other + * methods are inherited. This testcase explicitly tets the constructors but also + * implicitly tests some of the inherited query methods. + * + */ + +public class SQLPermissionTest extends TestCase { + + /* + * Constructor test + */ + public void testSQLPermissionStringString() { + String validName = "setLog"; + String validActions = "theActions"; + + SQLPermission thePermission = new SQLPermission(validName, validActions); + + assertNotNull(thePermission); + assertEquals(validName, thePermission.getName()); + // System.out.println("The actions: " + thePermission.getActions() + "." + // ); + assertEquals("", thePermission.getActions()); + } // end method testSQLPermissionStringString + + /* + * Constructor test + */ + public void testSQLPermissionString() { + String validName = "setLog"; + + SQLPermission thePermission = new SQLPermission(validName); + + assertNotNull(thePermission); + assertEquals(validName, thePermission.getName()); + + // Set an invalid name ... + String invalidName = "foo"; + + thePermission = new SQLPermission(invalidName); + + assertNotNull(thePermission); + assertEquals(invalidName, thePermission.getName()); + assertEquals("", thePermission.getActions()); + } // end method testSQLPermissionString + +} // end class SQLPermissionTest + + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.java new file mode 100644 index 0000000..d0998ce --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.java @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.Serializable; +import java.sql.SQLException; +import java.sql.SQLWarning; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; + +import junit.framework.TestCase; + +public class SQLWarningTest extends TestCase { + + /* + * ConstructorTest + */ + public void testSQLWarning() { + + String[] theFinalStates1 = { null }; + String[] theFinalStates2 = { null }; + int[] theFinalStates3 = { 0 }; + SQLWarning[] theFinalStates4 = { null }; + + Exception[] theExceptions = { null }; + + SQLWarning aSQLWarning; + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLWarning + + /* + * ConstructorTest + */ + public void testSQLWarningString() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, + "", "\u0000" }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = { null, null, null, null, null, null, null, + null }; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0, 0 }; + SQLWarning[] theFinalStates4 = { null, null, null, null, null, null, + null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null }; + + SQLWarning aSQLWarning; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(init1[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLWarningString + + /* + * ConstructorTest + */ + public void testSQLWarningStringString() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", null, "", + "\u0000", "a", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "a", "a", + "a", null, "", "\u0000" }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + SQLWarning[] theFinalStates4 = { null, null, null, null, null, null, + null, null, null, null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null }; + + SQLWarning aSQLWarning; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(init1[i], init2[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLWarningStringString + + /* + * ConstructorTest + */ + public void testSQLWarningStringStringint() { + + String[] init1 = { "a", "1", "valid1", "----", "&valid*", "----", + "----", null, "", "\u0000", "a", "a", "a" }; + String[] init2 = { "a", "1", "valid1", "----", "&valid*", "valid1", + "----", "a", "a", "a", null, "", "\u0000" }; + int[] init3 = { -2147483648, 2147483647, 0, 1412862821, -733923487, + 488067774, -1529953616, -2147483648, -2147483648, -2147483648, + -2147483648, -2147483648, -2147483648 }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = init2; + int[] theFinalStates3 = init3; + SQLWarning[] theFinalStates4 = { null, null, null, null, null, null, + null, null, null, null, null, null, null }; + + Exception[] theExceptions = { null, null, null, null, null, null, null, + null, null, null, null, null, null }; + + SQLWarning aSQLWarning; + int loopCount = init1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(init1[i], init2[i], init3[i]); + if (theExceptions[i] != null) { + fail(); + } + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSQLWarningStringStringint + + /* + * Method test for getNextWarning + */ + public void testGetNextWarning() { + + SQLWarning aSQLWarning; + String[] init1 = { "a", "1", "valid1", "----", "&valid*" }; + + SQLWarning theReturn; + SQLWarning[] theReturns = { null }; + String[] theFinalStates1 = init1; + String[] theFinalStates2 = { null }; + int[] theFinalStates3 = { 0 }; + SQLWarning[] theFinalStates4 = { null }; + + Exception[] theExceptions = { null }; + + int loopCount = 1; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(init1[i]); + theReturn = aSQLWarning.getNextWarning(); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + "Return value mismatch", theReturn, + theReturns[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testGetNextWarning + + /* + * Method test for setNextWarning + */ + public void testSetNextWarningSQLWarning() { + + SQLWarning[] parm1 = { new SQLWarning(), null }; + + SQLWarning aSQLWarning; + String[] init1 = { "a", "1" }; + + String[] theFinalStates1 = init1; + String[] theFinalStates2 = { null, null }; + int[] theFinalStates3 = { 0, 0 }; + SQLWarning[] theFinalStates4 = parm1; + + Exception[] theExceptions = { null, null }; + + int loopCount = parm1.length; + for (int i = 0; i < loopCount; i++) { + try { + aSQLWarning = new SQLWarning(init1[i]); + aSQLWarning.setNextWarning(parm1[i]); + if (theExceptions[i] != null) { + fail(i + "Exception missed"); + } + assertEquals(i + " Final state mismatch", aSQLWarning + .getMessage(), theFinalStates1[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getSQLState(), theFinalStates2[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getErrorCode(), theFinalStates3[i]); + assertEquals(i + " Final state mismatch", aSQLWarning + .getNextWarning(), theFinalStates4[i]); + + } catch (Exception e) { + if (theExceptions[i] == null) { + fail(i + "Unexpected exception"); + } + assertEquals(i + "Exception mismatch", e.getClass(), + theExceptions[i].getClass()); + assertEquals(i + "Exception mismatch", e.getMessage(), + theExceptions[i].getMessage()); + } // end try + } // end for + + } // end method testSetNextWarningSQLWarning + + /** + * @tests java.sql.SQLWarning#setNextWarning(java.sql.SQLWarning) + */ + public void test_setNextWarning_SQLWarning() { + SQLWarning sw = new SQLWarning("reason", "SQLState", 0); + SQLWarning sw1 = new SQLWarning("reason", "SQLState", 1); + SQLWarning sw2 = new SQLWarning("reason", "SQLState", 2); + SQLWarning sw3 = new SQLWarning("reason", "SQLState", 3); + + SQLException se = new SQLException("reason", "SQLState", 4); + + sw.setNextWarning(sw1); + assertSame(sw1, sw.getNextException()); + assertSame(sw1, sw.getNextWarning()); + + + sw.setNextWarning(sw2); + assertSame(sw2, sw1.getNextException()); + assertSame(sw2, sw1.getNextWarning()); + + sw.setNextException(sw3); + assertSame(sw3, sw2.getNextException()); + assertSame(sw3, sw2.getNextWarning()); + + sw.setNextException(se); + assertSame(se, sw3.getNextException()); + try { + sw3.getNextWarning(); + fail("should throw Error"); + } catch (Error e) { + //expected + } + } + + /** + * @tests serialization/deserialization compatibility. + */ + public void testSerializationSelf() throws Exception { + SQLWarning object = new SQLWarning(); + SerializationTest.verifySelf(object, SQLWARNING_COMPARATOR); + } + + /** + * @tests serialization/deserialization compatibility with RI. + */ + public void testSerializationCompatibility() throws Exception { + SQLWarning object = new SQLWarning(); + + SQLWarning nextSQLWarning = new SQLWarning("nextReason", + "nextSQLState", 10); + + object.setNextWarning(nextSQLWarning); + + SerializationTest.verifyGolden(this, object, SQLWARNING_COMPARATOR); + } + + // comparator for SQLWarning objects + private static final SerializableAssert SQLWARNING_COMPARATOR = new SerializableAssert() { + public void assertDeserialized(Serializable initial, + Serializable deserialized) { + + // do common checks for all throwable objects + SerializationTest.THROWABLE_COMPARATOR.assertDeserialized(initial, + deserialized); + + SQLWarning initThr = (SQLWarning) initial; + SQLWarning dserThr = (SQLWarning) deserialized; + + // verify getNextWarning() method + if (initThr.getNextWarning() == null) { + assertNull(dserThr.getNextWarning()); + } else { + // use the same comparator + SQLWARNING_COMPARATOR.assertDeserialized(initThr + .getNextWarning(), dserThr.getNextWarning()); + } + } + }; + +} // end class SQLWarningTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/StatementTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/StatementTest.java new file mode 100644 index 0000000..d0febeb --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/StatementTest.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class StatementTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("NO_GENERATED_KEYS", new Integer(2)); + thePublicStatics.put("RETURN_GENERATED_KEYS", new Integer(1)); + thePublicStatics.put("EXECUTE_FAILED", new Integer(-3)); + thePublicStatics.put("SUCCESS_NO_INFO", new Integer(-2)); + thePublicStatics.put("CLOSE_ALL_RESULTS", new Integer(3)); + thePublicStatics.put("KEEP_CURRENT_RESULT", new Integer(2)); + thePublicStatics.put("CLOSE_CURRENT_RESULT", new Integer(1)); + + /* + * System.out.println( "NO_GENERATED_KEYS: " + + * Statement.NO_GENERATED_KEYS ); System.out.println( + * "RETURN_GENERATED_KEYS: " + Statement.RETURN_GENERATED_KEYS ); + * System.out.println( "EXECUTE_FAILED: " + Statement.EXECUTE_FAILED ); + * System.out.println( "SUCCESS_NO_INFO: " + Statement.SUCCESS_NO_INFO ); + * System.out.println( "CLOSE_ALL_RESULTS: " + + * Statement.CLOSE_ALL_RESULTS ); System.out.println( + * "KEEP_CURRENT_RESULT: " + Statement.KEEP_CURRENT_RESULT ); + * System.out.println( "CLOSE_CURRENT_RESULT: " + + * Statement.CLOSE_CURRENT_RESULT ); + */ + + Class<?> statementClass; + try { + statementClass = Class.forName("java.sql.Statement"); + } catch (ClassNotFoundException e) { + fail("java.sql.Statement class not found!"); + return; + } // end try + + Field[] theFields = statementClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class StatementTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_ClassLoader.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_ClassLoader.java new file mode 100644 index 0000000..940a3aa --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_ClassLoader.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class TestHelper_ClassLoader extends ClassLoader { + + public TestHelper_ClassLoader() { + super(null); + } + + /** + * Loads a class specified by its name + * <p> + * This classloader makes the assumption that any class it is asked to load + * is in the current directory.... + */ + @Override + public Class<?> findClass(String className) throws ClassNotFoundException { + Class<?> theClass = null; + + if (!className.equals("org.apache.harmony.sql.tests.java.sql.TestHelper_DriverManager")) { + return null; + } + + String classNameAsFile = className.replace('.', '/') + ".class"; + // System.out.println("findClass - class filename = " + classNameAsFile + // ); + + String classPath = System.getProperty("java.class.path"); + // System.out.println("Test class loader - classpath = " + classPath ); + + String theSeparator = String.valueOf(File.pathSeparatorChar); + String[] theClassPaths = classPath.split(theSeparator); + for (int i = 0; (i < theClassPaths.length) && (theClass == null); i++) { + // Ignore jar files... + if (theClassPaths[i].endsWith(".jar")) { + theClass = loadClassFromJar(theClassPaths[i], className, + classNameAsFile); + } else { + theClass = loadClassFromFile(theClassPaths[i], className, + classNameAsFile); + } // end if + } // end for + + return theClass; + } // end method findClass( String ) + + @Override + public Class<?> loadClass(String className) throws ClassNotFoundException { + // Allowed classes: + String[] disallowedClasses = { "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver1", + "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver2", + "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver4", + "org.apache.harmony.sql.tests.java.sql.TestHelper_Driver5" }; + + Class<?> theClass; + + theClass = findLoadedClass(className); + if (theClass != null) { + return theClass; + } + + theClass = this.findClass(className); + + if (theClass == null) { + for (String element : disallowedClasses) { + if (element.equals(className)) { + return null; + } // end if + } // end for + theClass = Class.forName(className); + } // end if + + return theClass; + } // end method loadClass( String ) + + private Class<?> loadClassFromFile(String pathName, String className, + String classNameAsFile) { + Class<?> theClass = null; + FileInputStream theInput = null; + File theFile = null; + try { + theFile = new File(pathName, classNameAsFile); + if (theFile.exists()) { + int length = (int) theFile.length(); + theInput = new FileInputStream(theFile); + byte[] theBytes = new byte[length + 100]; + int dataRead = 0; + while (dataRead < length) { + int count = theInput.read(theBytes, dataRead, + theBytes.length - dataRead); + if (count == -1) { + break; + } + dataRead += count; + } + + if (dataRead > 0) { + // Create the class from the bytes read in... + theClass = this.defineClass(className, theBytes, 0, dataRead); + ClassLoader testClassLoader = theClass.getClassLoader(); + if (testClassLoader != this) { + System.out.println("findClass - wrong classloader!!"); + } + } + } + } catch (Exception e) { + System.out.println("findClass - exception reading class file."); + e.printStackTrace(); + } finally { + try { + if (theInput != null) { + theInput.close(); + } + } catch (Exception e) { + } + } + return theClass; + } + + /* + * Loads a named class from a specified JAR file + */ + private Class<?> loadClassFromJar(String jarfileName, String className, + String classNameAsFile) { + Class<?> theClass = null; + + // First, try to open the Jar file + JarFile theJar = null; + try { + theJar = new JarFile(jarfileName); + JarEntry theEntry = theJar.getJarEntry(classNameAsFile); + + if (theEntry == null) { + // System.out.println("TestHelper_Classloader - did not find + // class file in Jar " + jarfileName ); + return theClass; + } // end if + + theEntry.getMethod(); + InputStream theStream = theJar.getInputStream(theEntry); + + long size = theEntry.getSize(); + if (size < 0) { + size = 100000; + } + byte[] theBytes = new byte[(int) size + 100]; + + int dataRead = 0; + while (dataRead < size) { + int count = theStream.read(theBytes, dataRead, theBytes.length + - dataRead); + if (count == -1) { + break; + } + dataRead += count; + } // end while + + // System.out.println("loadClassFromJar: read " + dataRead + " bytes + // from class file"); + if (dataRead > 0) { + // Create the class from the bytes read in... + theClass = this.defineClass(className, theBytes, 0, dataRead); + /* System.out.println("findClass: created Class object."); */ + ClassLoader testClassLoader = theClass.getClassLoader(); + if (testClassLoader != this) { + System.out.println("findClass - wrong classloader!!"); + } else { + System.out + .println("Testclassloader loaded class from jar: " + + className); + } // end if + } // end if + } catch (IOException ie) { + System.out + .println("TestHelper_ClassLoader: IOException opening Jar " + + jarfileName); + } catch (Exception e) { + System.out + .println("TestHelper_ClassLoader: Exception loading class from Jar "); + } catch (ClassFormatError ce) { + System.out + .println("TestHelper_ClassLoader: ClassFormatException loading class from Jar "); + } finally { + try { + if (theJar != null) { + theJar.close(); + } + } catch (Exception e) { + } // end try + } // end try + + return theClass; + } // end method loadClassFromJar( + +} // end class TestHelper_ClassLoader + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Connection1.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Connection1.java new file mode 100644 index 0000000..8b1fd60 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Connection1.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Savepoint; +import java.sql.Statement; +import java.util.Map; + +/** + * Helper class for the java.sql tests - a skeleton class which implements the + * java.sql.Connection interface + * + */ +public class TestHelper_Connection1 implements Connection { + public void clearWarnings() throws SQLException { + } + + public void close() throws SQLException { + } + + public void commit() throws SQLException { + } + + public Statement createStatement() throws SQLException { + return null; + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return null; + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException { + return null; + } + + public boolean getAutoCommit() throws SQLException { + return false; + } + + public String getCatalog() throws SQLException { + return null; + } + + public int getHoldability() throws SQLException { + return 0; + } + + public DatabaseMetaData getMetaData() throws SQLException { + return null; + } + + public int getTransactionIsolation() throws SQLException { + return 0; + } + + public Map<String, Class<?>> getTypeMap() throws SQLException { + return null; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public boolean isClosed() throws SQLException { + return false; + } + + public boolean isReadOnly() throws SQLException { + return false; + } + + public String nativeSQL(String sql) throws SQLException { + return null; + } + + public CallableStatement prepareCall(String sql, int resultSetType, + int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + return null; + } + + public CallableStatement prepareCall(String sql) throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, + int resultSetConcurrency) throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) + throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) + throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql, String[] columnNames) + throws SQLException { + return null; + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + return null; + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + } + + public void rollback() throws SQLException { + } + + public void rollback(Savepoint savepoint) throws SQLException { + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + } + + public void setCatalog(String catalog) throws SQLException { + } + + public void setHoldability(int holdability) throws SQLException { + } + + public void setReadOnly(boolean readOnly) throws SQLException { + } + + public Savepoint setSavepoint() throws SQLException { + return null; + } + + public Savepoint setSavepoint(String name) throws SQLException { + return null; + } + + public void setTransactionIsolation(int level) throws SQLException { + } + + public void setTypeMap(Map<String, Class<?>> map) throws SQLException { + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver1.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver1.java new file mode 100644 index 0000000..ae09f94 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver1.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.Properties; + +/** + * A simple implementation of a class implementing a JDBC Driver, for use in the + * testing of the java.sql.DriverManager class + * + */ +public class TestHelper_Driver1 implements Driver { + int majorVersion = 1; + + int minorVersion = 0; + + String baseURL = "jdbc:mikes1"; + + String[] dataSources = { "data1", "data2", "data3" }; + + static Driver theDriver; + static { + theDriver = new TestHelper_Driver1(); + try { + DriverManager.registerDriver(theDriver); + } catch (SQLException e) { + System.out.println("Failed to register driver!"); + } + } // end static block initializer + + protected TestHelper_Driver1() { + super(); + } // end constructor TestHelper_Driver1() + + public boolean acceptsURL(String url) throws SQLException { + // Check on the supplied String... + if (url == null) { + return false; + } + // Everything's fine if the quoted url starts with the base url for this + // driver + if (url.startsWith(baseURL)) { + return true; + } + return false; + } // end method acceptsURL + + static String validuser = "theuser"; + + static String validpassword = "thepassword"; + + static String userProperty = "user"; + + static String passwordProperty = "password"; + + public Connection connect(String url, Properties info) throws SQLException { + // Does the URL have the right form? + if (this.acceptsURL(url)) { + // The datasource name is the remainder of the url after the ":" + String datasource = url.substring(baseURL.length() + 1); + for (String element : dataSources) { + if (datasource.equals(element)) { + /* + * Check for user and password, except for datasource = + * data1 which is set up not to require a user/password + * combination + */ + // It all checks out - so return a connection + Connection connection = new TestHelper_Connection1(); + return connection; + } // end if + } // end for + } // end if + return null; + } // end method connect(String, Properties) + + public int getMajorVersion() { + return majorVersion; + } // end method getMajorVersion() + + public int getMinorVersion() { + return minorVersion; + } // end method getMinorVersion() + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) + throws SQLException { + DriverPropertyInfo[] theInfos = { new DriverPropertyInfo(userProperty, "*"), + new DriverPropertyInfo(passwordProperty, "*"), }; + return theInfos; + } + + public boolean jdbcCompliant() { + // Basic version here returns false + return false; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver2.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver2.java new file mode 100644 index 0000000..6d495d6 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver2.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Basic JDBC driver implementation to help with tests + * + */ +public class TestHelper_Driver2 extends TestHelper_Driver1 { + + static { + Driver theDriver = new TestHelper_Driver2(); + /* + * System.out.println("Driver2 classloader: " + + * theDriver.getClass().getClassLoader() ); System.out.println("Driver2 + * object is: " + theDriver ); + */ + try { + DriverManager.registerDriver(theDriver); + } catch (SQLException e) { + System.out.println("Failed to register driver!"); + } + } // end static block initializer + + protected TestHelper_Driver2() { + super(); + baseURL = "jdbc:mikes2"; + } // end constructor TestHelper_Driver1() + +} // end class TestHelper_Driver2 + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver3.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver3.java new file mode 100644 index 0000000..f02bdc3 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver3.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + + +/** + * TODO Type description + * + */ +public class TestHelper_Driver3 extends TestHelper_Driver1 { + + /* + * This driver does NOT automatically register itself... + */ + + public TestHelper_Driver3() { + super(); + baseURL = "jdbc:mikes3"; + } // end constructor TestHelper_Driver1() + +} // end class TestHelper_Driver3 diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver4.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver4.java new file mode 100644 index 0000000..655436d --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver4.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.Properties; + +/** + * Basic JDBC driver implementation to help with tests + * + */ +public class TestHelper_Driver4 implements Driver { + int majorVersion = 1; + + int minorVersion = 0; + + String baseURL; + + String[] dataSources = { "data1", "data2", "data3" }; + static { + Driver theDriver = new TestHelper_Driver4(); + try { + DriverManager.registerDriver(theDriver); + } catch (SQLException e) { + System.out.println("Failed to register driver!"); + } + } // end static block initializer + + protected TestHelper_Driver4() { + super(); + baseURL = "jdbc:mikes4"; + } // end constructor TestHelper_Driver4() + + public boolean acceptsURL(String url) throws SQLException { + // Check on the supplied String... + if (url == null) { + return false; + } + // Everything's fine if the quoted url starts with the base url for this + // driver + if (url.startsWith(baseURL)) { + return true; + } + return false; + } // end method acceptsURL + + static String validuser = "theuser"; + + static String validpassword = "thepassword"; + + static String userProperty = "user"; + + static String passwordProperty = "password"; + + public Connection connect(String url, Properties info) throws SQLException { + // Does the URL have the right form? + if (this.acceptsURL(url)) { + // The datasource name is the remainder of the url after the ":" + String datasource = url.substring(baseURL.length() + 1); + for (String element : dataSources) { + if (datasource.equals(element)) { + /* + * Check for user and password, except for datasource = + * data1 which is set up not to require a user/password + * combination + */ + if (datasource.equals("data1")) { + // do nothing... + } else { + if (info == null) { + throw new SQLException("Properties bundle is null"); + } + String user = (String) info.get(userProperty); + String password = (String) info.get(passwordProperty); + if (user == null || password == null) { + throw new SQLException("Userid and/or password not supplied"); + } + if (!user.equals(validuser) || !password.equals(validpassword)) { + throw new SQLException("Userid and/or password not valid"); + } // end if + } // end if + // It all checks out - so return a connection + Connection connection = new TestHelper_Connection1(); + return connection; + } // end if + } // end for + } // end if + return null; + } // end method connect(String, Properties) + + public int getMajorVersion() { + return majorVersion; + } // end method getMajorVersion() + + public int getMinorVersion() { + return minorVersion; + } // end method getMinorVersion() + + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) + throws SQLException { + DriverPropertyInfo[] theInfos = { new DriverPropertyInfo(userProperty, "*"), + new DriverPropertyInfo(passwordProperty, "*"), }; + return theInfos; + } + + public boolean jdbcCompliant() { + // Basic version here returns false + return false; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver5.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver5.java new file mode 100644 index 0000000..b228466 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_Driver5.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Basic JDBC driver implementation to help with tests + * + */ +public class TestHelper_Driver5 extends TestHelper_Driver4 { + + static { + Driver theDriver = new TestHelper_Driver5(); + try { + DriverManager.registerDriver(theDriver); + } catch (SQLException e) { + System.out.println("Failed to register driver!"); + } + } // end static block initializer + + protected TestHelper_Driver5() { + super(); + baseURL = "jdbc:mikes5"; + } // end constructor TestHelper_Driver5() + +} // end class TestHelper_Driver5 diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_DriverManager.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_DriverManager.java new file mode 100644 index 0000000..299c33a --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TestHelper_DriverManager.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; + +import junit.framework.TestCase; + +/** + * Helper class for the Driver manager tes - it allows the test code to be + * loaded under a different classloader, necessary for testing the + * DeregisterDriver function of DriverManager + * + */ +public class TestHelper_DriverManager extends TestCase { + + static Driver testDriver = null; + + static TestHelper_DriverManager theHelper; + + static { + theHelper = new TestHelper_DriverManager(); + // theHelper.testDeregister(); + } // end static + + public TestHelper_DriverManager() { + super(); + } // end constructor TestHelper_DriverManager() + + public static void setDriver(Driver theDriver) { + testDriver = theDriver; + // System.out.println("TestHelper_DriverManager: Test Driver set!"); + + theHelper.checkDeregister(); + } // end method setDriver( Driver ) + + public void checkDeregister() { + + String baseURL = "jdbc:mikes1"; + + // System.out.println("Calling checkDeregister in + // TestHelper_DriverManager...."); + + Driver aDriver; + + // System.out.println("checkDeregister classloader: " + + // this.getClass().getClassLoader() ); + + // Try to get a driver from the general pool... this should fail + try { + aDriver = DriverManager.getDriver(baseURL); + fail( + "testDeregisterDriver: Didn't get exception when getting valid driver from other classloader."); + } catch (SQLException e) { + // e.printStackTrace(); + assertTrue( + "testDeregisterDriver: Got exception when getting valid driver from other classloader.", + true); + // return; + } // end try + + // OK, now THIS driver was loaded by someone else.... + aDriver = testDriver; + + // printClassLoader( aDriver ); + + // Deregister this driver + try { + DriverManager.deregisterDriver(aDriver); + // We shouldn't get here - but if we do, we need to re-register the + // driver to + // prevent subsequent tests from failing due to inability to get to + // this driver... + DriverManager.registerDriver(aDriver); + fail( + "checkDeregisterDriver: Didn't get Security Exception deregistering invalid driver."); + } catch (SecurityException s) { + // This is the exception we should get... + // System.out.println("checkDeregisterDriver: got expected Security + // Exception"); + } catch (Exception e) { + fail( + "checkDeregisterDriver: Got wrong exception type when deregistering invalid driver."); + } // end try + + } // end method testDeRegister + + static void printClassLoader(Object theObject) { + Class<? extends Object> theClass = theObject.getClass(); + ClassLoader theClassLoader = theClass.getClassLoader(); + System.out.println("ClassLoader is: " + theClassLoader.toString() + + " for object: " + theObject.toString()); + } // end method printClassLoader( Object ) + +} // end class TestHelper_DriverManager + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimeTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimeTest.java new file mode 100644 index 0000000..a523b39 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimeTest.java @@ -0,0 +1,304 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Time; +import java.util.TimeZone; + +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.Time class + * + */ +public class TimeTest extends TestCase { + + static long TIME_TEST1 = 38720000; // 10:45:20 GMT + + static long TIME_TEST2 = 80279000; // 22:17:59 GMT + + static long TIME_TEST3 = -38720000; // 13:14:40 GMT + + static String STRING_TEST1 = "10:45:20"; + + static String STRING_TEST2 = "22:17:59"; + + static String STRING_TEST3 = "13:14:40"; + + static String STRING_INVALID1 = "ABCDEFGHI"; + + static String STRING_INVALID2 = "233104"; + + static String STRING_INVALID3 = "21-43-48"; + + static String STRING_OUTRANGE = "35:99:66"; + + static long[] TIME_ARRAY = { TIME_TEST1, TIME_TEST2, TIME_TEST3 }; + + static String[] STRING_GMT_ARRAY = { STRING_TEST1, STRING_TEST2, + STRING_TEST3 }; + + static String[] STRING_LA_ARRAY = { "02:45:20", "14:17:59", "05:14:40" }; + + static String[] STRING_JP_ARRAY = { "19:45:20", "07:17:59", "22:14:40" }; + + static String[] INVALID_STRINGS = { STRING_INVALID1, STRING_INVALID2, + STRING_INVALID3 }; + + // Timezones + static String TZ_LONDON = "GMT"; // GMT (!) PS London != GMT (?!?) + + static String TZ_PACIFIC = "America/Los_Angeles"; // GMT - 8 + + static String TZ_JAPAN = "Asia/Tokyo"; // GMT + 9 + + static String[] TIMEZONES = { TZ_LONDON, TZ_PACIFIC, TZ_JAPAN }; + + static String[][] STRING_ARRAYS = { STRING_GMT_ARRAY, STRING_LA_ARRAY, + STRING_JP_ARRAY }; + + @SuppressWarnings("deprecation") + public void testTimeintintint() { + Time theTime = new Time(10, 45, 20); + + // The date should have been created + assertNotNull(theTime); + } // end method testTimeintintint() + + public void testTime() { + Time theTime = new Time(TIME_TEST1); + + // The date should have been created + assertNotNull(theTime); + } // end method testTime() + + public void testToString() { + // Loop through the timezones testing the String conversion for each + for (int i = 0; i < TIME_ARRAY.length; i++) { + testToString(TIMEZONES[i], TIME_ARRAY, STRING_ARRAYS[i]); + } // end for + + } // end method test + + private void testToString(String timeZone, long[] theTimes, + String[] theTimeStrings) { + // Set the timezone + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + + for (int i = 0; i < theTimes.length; i++) { + // Create the Time object + Time theTime = new Time(theTimes[i]); + // Convert to a time string ... and compare + String JDBCString = theTime.toString(); + assertEquals(theTimeStrings[i], JDBCString); + } // end for + + } // end testToString( String, long[], String[] ) + + /* + * Method test for valueOf + */ + public void testValueOfString() { + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + + Time[] theReturns = { new Time(38720000), new Time(80279000), + new Time(47680000)}; + String[] validTime = { "10:45:20", "22:17:59", "13:14:40", }; + String[] invalidTime = { null, "ABCDEFGHI", "233104", "21-43-48" }; + + for (int i = 0; i < validTime.length; i++) { + Time theReturn = Time.valueOf(validTime[i]); + assertEquals(theReturns[i], theReturn); + } // end for + + for (String element : invalidTime) { + try { + Time.valueOf(element); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + } + + } // end method testValueOfString + + public void testSetTime() { + // Ensure that the timezone is set to GMT + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + Time theTime = new Time(TIME_TEST1); + assertEquals(STRING_TEST1, theTime.toString()); + + theTime.setTime(TIME_TEST2); + assertEquals(STRING_TEST2, theTime.toString()); + } // end method testSetTime() + + @SuppressWarnings("deprecation") + public void testSetDate() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.setDate(10); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method testSetDate() + + @SuppressWarnings("deprecation") + public void testSetMonth() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.setMonth(2); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method testSetMonth() + + @SuppressWarnings("deprecation") + public void testSetYear() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.setYear(99); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method testSetYear() + + @SuppressWarnings("deprecation") + public void testGetDate() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.getDate(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method test + + @SuppressWarnings("deprecation") + public void testGetDay() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.getDay(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method test + + @SuppressWarnings("deprecation") + public void testGetMonth() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.getMonth(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method test + + @SuppressWarnings("deprecation") + public void testGetYear() { + Time theTime = new Time(TIME_TEST1); + + try { + theTime.getYear(); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + } // end method test + + /** + * @tests java.sql.Time#valueOf(String ) + */ + public void test_valueOf_IllegalArgumentException() { + try{ + Time.valueOf("15:43:12:34"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + + try{ + Time.valueOf(":10:07:01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf("::01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf("11::"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf(":01:"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf(":10:w2:01"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf("07:w2:"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } + + try{ + Time.valueOf("17:w2:w2"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + + try{ + Time.valueOf("16::01"); + fail("should throw NumberFormatException"); + } catch (NumberFormatException e) { + //expected + } + } +} // end class TimeTest + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimestampTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimestampTest.java new file mode 100644 index 0000000..7c5d7ab --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TimestampTest.java @@ -0,0 +1,624 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.TimeZone; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import junit.framework.TestCase; + +/** + * JUnit Testcase for the java.sql.Timestamp class + * + */ + +public class TimestampTest extends TestCase { + + static long TIME_TEST1 = 38720231; // 10:45:20.231 GMT + + static long TIME_TEST2 = 80279000; // 22:17:59.000 GMT + + static long TIME_TEST3 = -38720691; // 13:14:39.309 GMT + + static long TIME_COMPARE = 123498845; + + static long TIME_EARLY = -2347889122L;// A time well before the Epoch + + static long TIME_LATE = 2347889122L; // A time well after the Epoch + + static String STRING_TEST1 = "1970-01-01 10:45:20.231"; // "1970-01-01 + // 10:45:20.231000000"; + + static String STRING_TEST2 = "1970-01-01 22:17:59.0"; // "1970-01-01 + // 22:17:59.000000000"; + + static String STRING_TEST3 = "1969-12-31 13:14:39.309"; // "1969-12-31 + // 13:14:39.309000000"; + + static String STRING_INVALID1 = "ABCDEFGHI"; + + static String STRING_INVALID2 = "233104"; + + static String STRING_INVALID3 = "21-43-48"; + + // A timepoint in the correct format but with numeric values out of range + // ...this is accepted despite being a crazy date specification + // ...it is treated as the correct format date 3000-06-08 12:40:06.875 !! + static String STRING_OUTRANGE = "2999-15-99 35:99:66.875"; + + static long[] TIME_ARRAY = { TIME_TEST1, TIME_TEST2, TIME_TEST3 }; + + static int[] YEAR_ARRAY = { 70, 70, 69 }; + + static int[] MONTH_ARRAY = { 0, 0, 11 }; + + static int[] DATE_ARRAY = { 1, 1, 31 }; + + static int[] HOURS_ARRAY = { 10, 22, 13 }; + + static int[] MINUTES_ARRAY = { 45, 17, 14 }; + + static int[] SECONDS_ARRAY = { 20, 59, 39 }; + + static int[] NANOS_ARRAY = { 231000000, 000000000, 309000000 }; + + static int[] NANOS_ARRAY2 = { 137891990, 635665198, 109985421 }; + + static String[] STRING_NANOS_ARRAY = { "1970-01-01 10:45:20.13789199", + "1970-01-01 22:17:59.635665198", "1969-12-31 13:14:39.109985421" }; + + static String[] STRING_GMT_ARRAY = { STRING_TEST1, STRING_TEST2, + STRING_TEST3 }; + + static String[] STRING_LA_ARRAY = { "02:45:20", "14:17:59", "05:14:40" }; + + static String[] STRING_JP_ARRAY = { "19:45:20", "07:17:59", "22:14:40" }; + + static String[] INVALID_STRINGS = { STRING_INVALID1, STRING_INVALID2, + STRING_INVALID3 }; + + // Timezones + static String TZ_LONDON = "GMT"; // GMT (!) PS London != GMT (?!?) + + static String TZ_PACIFIC = "America/Los_Angeles"; // GMT - 8 + + static String TZ_JAPAN = "Asia/Tokyo"; // GMT + 9 + + static String[] TIMEZONES = { TZ_LONDON, TZ_PACIFIC, TZ_JAPAN }; + + static String[][] STRING_ARRAYS = { STRING_GMT_ARRAY, STRING_LA_ARRAY, + STRING_JP_ARRAY }; + + /* + * Constructor test + */ + public void testTimestamplong() { + Timestamp theTimestamp = new Timestamp(TIME_TEST1); + + // The Timestamp should have been created + assertNotNull(theTimestamp); + } // end method testTimestamplong + + /* + * Constructor test + */ + @SuppressWarnings("deprecation") + public void testTimestampintintintintintintint() { + int[][] valid = { { 99, 2, 14, 17, 52, 3, 213577212 }, // 0 valid + { 0, 0, 1, 0, 0, 0, 0 }, // 1 valid + { 106, 11, 31, 23, 59, 59, 999999999 }, // 2 valid + { 106, 11, 31, 23, 59, 61, 999999999 }, // 5 Seconds out of + // range + { 106, 11, 31, 23, 59, -1, 999999999 }, // 6 Seconds out of + // range + { 106, 11, 31, 23, 61, 59, 999999999 }, // 7 Minutes out of + // range + { 106, 11, 31, 23, -1, 59, 999999999 }, // 8 Minutes out of + // range + { 106, 11, 31, 25, 59, 59, 999999999 }, // 9 Hours out of range + { 106, 11, 31, -1, 59, 59, 999999999 }, // 10 Hours out of range + { 106, 11, 35, 23, 59, 59, 999999999 }, // 11 Days out of range + { 106, 11, -1, 23, 59, 59, 999999999 }, // 12 Days out of range + { 106, 15, 31, 23, 59, 59, 999999999 }, // 13 Months out of + // range + { 106, -1, 31, 23, 59, 59, 999999999 }, // 14 Months out of + // range + { -10, 11, 31, 23, 59, 59, 999999999 }, // 15 valid - Years + // negative + }; + + for (int[] element : valid) { + Timestamp theTimestamp = new Timestamp(element[0], + element[1], element[2], element[3], + element[4], element[5], element[6]); + assertNotNull("Timestamp not generated: ", theTimestamp); + } // end for + + int[][] invalid = { + { 106, 11, 31, 23, 59, 59, 1999999999 }, + { 106, 11, 31, 23, 59, 59, -999999999 }, + }; + for (int[] element : invalid) { + try { + new Timestamp(element[0], + element[1], element[2], element[3], + element[4], element[5], element[6]); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + } // end method testTimestampintintintintintintint + + /* + * Method test for setTime + */ + public void testSetTimelong() { + // First set the timezone to GMT + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + Timestamp theTimestamp = new Timestamp(TIME_TEST1); + + for (int i = 0; i < TIME_ARRAY.length; i++) { + theTimestamp.setTime(TIME_ARRAY[i]); + + assertEquals(TIME_ARRAY[i], theTimestamp.getTime()); + assertEquals(NANOS_ARRAY[i], theTimestamp.getNanos()); + } // end for + + } // end method testsetTimelong + + /* + * Method test for getTime + */ + public void testGetTime() { + // First set the timezone to GMT + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + assertEquals(element, theTimestamp.getTime()); + } // end for + + } // end method testgetTime + + /* + * Method test for getYear + */ + @SuppressWarnings("deprecation") + public void testGetYear() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(YEAR_ARRAY[i], theTimestamp.getYear()); + } // end for + + } // end method testgetYear + + /* + * Method test for getMonth + */ + @SuppressWarnings("deprecation") + public void testGetMonth() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(MONTH_ARRAY[i], theTimestamp.getMonth()); + } // end for + + } // end method testgetMonth + + /* + * Method test for getDate + */ + @SuppressWarnings("deprecation") + public void testGetDate() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(DATE_ARRAY[i], theTimestamp.getDate()); + } // end for + + } // end method testgetDate + + /* + * Method test for getHours + */ + @SuppressWarnings("deprecation") + public void testGetHours() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(HOURS_ARRAY[i], theTimestamp.getHours()); + } // end for + + } // end method testgetHours + + /* + * Method test for getMinutes + */ + @SuppressWarnings("deprecation") + public void testGetMinutes() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(MINUTES_ARRAY[i], theTimestamp.getMinutes()); + } // end for + + } // end method testgetMinutes + + /* + * Method test for getSeconds + */ + @SuppressWarnings("deprecation") + public void testGetSeconds() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(SECONDS_ARRAY[i], theTimestamp.getSeconds()); + } // end for + + } // end method testgetSeconds + + /* + * Method test for valueOf + */ + static String theExceptionMessage = "Timestamp format must be yyyy-mm-dd hh:mm:ss.fffffffff"; + + public void testValueOfString() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + Timestamp theTimestamp2 = Timestamp.valueOf(STRING_GMT_ARRAY[i]); + assertEquals(theTimestamp, theTimestamp2); + } // end for + + // Test for a string in correct format but with number values out of + // range + Timestamp theTimestamp = Timestamp.valueOf(STRING_OUTRANGE); + assertNotNull(theTimestamp); + /* + * System.out.println("testValueOfString: outrange timestamp: " + + * theTimestamp.toString() ); + */ + + for (String element : INVALID_STRINGS) { + try { + Timestamp.valueOf(element); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } // end try + + } // end for + + } // end method testvalueOfString + + /* + * Method test for valueOf + */ + public void testValueOfString1() { + + Timestamp theReturn; + long[] theReturnTime = { 38720231, 38720231, 80279000, -38720691, + 38720000}; + int[] theReturnNanos = { 231000000, 231987654, 0, 309000000, 0,}; + + String[] valid = { + "1970-01-01 10:45:20.231", + "1970-01-01 10:45:20.231987654", + "1970-01-01 22:17:59.0", + "1969-12-31 13:14:39.309", + "1970-01-01 10:45:20", + }; + String[] invalid = { + null, + "ABCDEFGHI", + "233104", "1970-01-01 22:17:59.", + "1970-01-01 10:45:20.231987654690645322", + "1970-01-01 10:45:20&231987654", + "1970-01-01 10:45:20.-31987654", + "1970-01-01 10:45:20.ABCD87654", + "21-43-48", + }; + + for (int i = 0; i < valid.length; i++) { + theReturn = Timestamp.valueOf(valid[i]); + assertEquals(theReturnTime[i], theReturn.getTime()); + assertEquals(theReturnNanos[i], theReturn.getNanos()); + } // end for + + for (String element : invalid) { + try { + theReturn = Timestamp.valueOf(element); + fail("Should throw IllegalArgumentException."); + } catch (IllegalArgumentException e) { + //expected + } + } + + } // end method testValueOfString + + /* + * Method test for toString + */ + public void testToString() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(STRING_GMT_ARRAY[i], theTimestamp.toString()); + } // end for + + } // end method testtoString + + /* + * Method test for getNanos + */ + public void testGetNanos() { + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + assertEquals(NANOS_ARRAY[i], theTimestamp.getNanos()); + } // end for + + } // end method testgetNanos + + /* + * Method test for setNanos + */ + public void testSetNanosint() { + int[] NANOS_INVALID = { -137891990, 1635665198, -1 }; + for (int i = 0; i < TIME_ARRAY.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + + theTimestamp.setNanos(NANOS_ARRAY2[i]); + + assertEquals(NANOS_ARRAY2[i], theTimestamp.getNanos()); + // Also check that these Timestamps with detailed nanos values + // convert to + // strings correctly + assertEquals(STRING_NANOS_ARRAY[i], theTimestamp.toString()); + } // end for + + for (int i = 0; i < NANOS_INVALID.length; i++) { + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[i]); + int originalNanos = theTimestamp.getNanos(); + try { + theTimestamp.setNanos(NANOS_INVALID[i]); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + //expected + } // end try + + assertEquals(originalNanos, theTimestamp.getNanos()); + } // end for + + } // end method testsetNanosint + + /* + * Method test for equals + */ + public void testEqualsTimestamp() { + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + Timestamp theTimestamp2 = new Timestamp(element); + + assertTrue(theTimestamp.equals(theTimestamp2)); + } // end for + + Timestamp theTest = new Timestamp(TIME_COMPARE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + assertFalse(theTimestamp.equals(theTest)); + } // end for + + // Regression for HARMONY-526 + assertFalse(new Timestamp(0).equals((Timestamp) null)); + } // end method testequalsTimestamp + + /* + * Method test for equals + */ + public void testEqualsObject() { + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + Object theTimestamp2 = new Timestamp(element); + + assertTrue(theTimestamp.equals(theTimestamp2)); + } // end for + + Object theTest = new Timestamp(TIME_COMPARE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + assertFalse(theTimestamp.equals(theTest)); + } // end for + + Object nastyTest = new String("Test "); + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[1]); + assertFalse(theTimestamp.equals(nastyTest)); + + // Regression for HARMONY-526 + assertFalse(new Timestamp(0).equals((Object) null)); + } // end method testequalsObject + + /* + * Method test for before + */ + public void testBeforeTimestamp() { + Timestamp theTest = new Timestamp(TIME_LATE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + assertTrue(theTimestamp.before(theTest)); + } // end for + + theTest = new Timestamp(TIME_EARLY); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + assertFalse(theTimestamp.before(theTest)); + } // end for + + for (long element : TIME_ARRAY) { + theTest = new Timestamp(element); + Timestamp theTimestamp = new Timestamp(element); + + assertFalse(theTimestamp.before(theTest)); + theTest.setNanos(theTest.getNanos() + 1); + assertTrue(theTimestamp.before(theTest)); + } // end for + + } // end method testbeforeTimestamp + + /* + * Method test for after + */ + public void testAfterTimestamp() { + Timestamp theTest = new Timestamp(TIME_LATE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + assertFalse(theTimestamp.after(theTest)); + } // end for + + theTest = new Timestamp(TIME_EARLY); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + + assertTrue(theTimestamp.after(theTest)); + } // end for + + for (long element : TIME_ARRAY) { + theTest = new Timestamp(element); + Timestamp theTimestamp = new Timestamp(element); + + assertFalse(theTimestamp.after(theTest)); + theTimestamp.setNanos(theTimestamp.getNanos() + 1); + assertTrue(theTimestamp.after(theTest)); + } // end for + + } // end method testafterTimestamp + + /* + * Method test for compareTo + */ + @SuppressWarnings("deprecation") + public void testCompareToTimestamp() { + Timestamp theTest = new Timestamp(TIME_EARLY); + Timestamp theTest2 = new Timestamp(TIME_LATE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + Timestamp theTimestamp2 = new Timestamp(element); + + assertTrue(theTimestamp.compareTo(theTest) > 0); + assertTrue(theTimestamp.compareTo(theTest2) < 0); + assertEquals(0, theTimestamp.compareTo(theTimestamp2)); + } // end for + + Timestamp t1 = new Timestamp(-1L); + Timestamp t2 = new Timestamp(-1L); + + t1.setTime(Long.MIN_VALUE); + t2.setDate(Integer.MIN_VALUE); + assertEquals(1, t1.compareTo(t2)); + assertEquals(-1, t2.compareTo(t1)); + + t1.setTime(Long.MAX_VALUE); + t2.setTime(Long.MAX_VALUE - 1); + assertEquals(1, t1.compareTo(t2)); + assertEquals(-1, t2.compareTo(t1)); + + t1.setTime(Integer.MAX_VALUE); + t2.setTime(Integer.MAX_VALUE); + assertEquals(0, t1.compareTo(t2)); + assertEquals(0, t2.compareTo(t1)); + + } // end method testcompareToTimestamp + + /** + * @tests java.sql.Timestamp#compareTo(java.util.Date) + */ + public void testCompareToDate() { + Date theTest = new Timestamp(TIME_EARLY); + Date theTest2 = new Timestamp(TIME_LATE); + + for (long element : TIME_ARRAY) { + Timestamp theTimestamp = new Timestamp(element); + Date theTimestamp2 = new Timestamp(element); + + assertTrue(theTimestamp.compareTo(theTest) > 0); + assertTrue(theTimestamp.compareTo(theTest2) < 0); + assertEquals(0, theTimestamp.compareTo(theTimestamp2)); + } // end for + + Date nastyTest = new Date(); + Timestamp theTimestamp = new Timestamp(TIME_ARRAY[1]); + try { + theTimestamp.compareTo(nastyTest); + // It throws ClassCastException in JDK 1.5.0_06 but in 1.5.0_07 it + // does not throw the expected exception. + fail("testCompareToObject: Did not get expected ClassCastException"); + } catch (ClassCastException e) { + // Should get here + /* + * System.out.println("testCompareToObject: ClassCastException as + * expected"); System.out.println("Exception message: " + + * e.getMessage()); + */ + } // end try + + } // end method testcompareToObject + + /** + * @tests serialization/deserialization compatibility. + */ + public void testSerializationSelf() throws Exception { + Timestamp object = new Timestamp(100L); + SerializationTest.verifySelf(object); + } + + /** + * @tests serialization/deserialization compatibility with RI. + */ + public void testSerializationCompatibility() throws Exception { + Timestamp object = new Timestamp(100L); + SerializationTest.verifyGolden(this, object); + } + + /** + * @tests java.sql.Timestamp#toString() + */ + public void test_toString() { + + Timestamp t1 = new Timestamp(Long.MIN_VALUE); + assertEquals("292278994-08-17 07:12:55.192", t1.toString()); //$NON-NLS-1$ + + Timestamp t2 = new Timestamp(Long.MIN_VALUE + 1); + assertEquals("292278994-08-17 07:12:55.193", t2.toString()); //$NON-NLS-1$ + + Timestamp t3 = new Timestamp(Long.MIN_VALUE + 807); + assertEquals("292278994-08-17 07:12:55.999", t3.toString()); //$NON-NLS-1$ + + Timestamp t4 = new Timestamp(Long.MIN_VALUE + 808); + assertEquals("292269055-12-02 16:47:05.0", t4.toString()); //$NON-NLS-1$ + } + +} // end class TimestampTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TypesTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TypesTest.java new file mode 100644 index 0000000..5ee8860 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/java/sql/TypesTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.java.sql; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import junit.framework.TestCase; + +public class TypesTest extends TestCase { + + /* + * Public statics test + */ + public void testPublicStatics() { + + HashMap<String, Integer> thePublicStatics = new HashMap<String, Integer>(); + thePublicStatics.put("BOOLEAN", new Integer(16)); + thePublicStatics.put("DATALINK", new Integer(70)); + thePublicStatics.put("REF", new Integer(2006)); + thePublicStatics.put("CLOB", new Integer(2005)); + thePublicStatics.put("BLOB", new Integer(2004)); + thePublicStatics.put("ARRAY", new Integer(2003)); + thePublicStatics.put("STRUCT", new Integer(2002)); + thePublicStatics.put("DISTINCT", new Integer(2001)); + thePublicStatics.put("JAVA_OBJECT", new Integer(2000)); + thePublicStatics.put("OTHER", new Integer(1111)); + thePublicStatics.put("NULL", new Integer(0)); + thePublicStatics.put("LONGVARBINARY", new Integer(-4)); + thePublicStatics.put("VARBINARY", new Integer(-3)); + thePublicStatics.put("BINARY", new Integer(-2)); + thePublicStatics.put("TIMESTAMP", new Integer(93)); + thePublicStatics.put("TIME", new Integer(92)); + thePublicStatics.put("DATE", new Integer(91)); + thePublicStatics.put("LONGVARCHAR", new Integer(-1)); + thePublicStatics.put("VARCHAR", new Integer(12)); + thePublicStatics.put("CHAR", new Integer(1)); + thePublicStatics.put("DECIMAL", new Integer(3)); + thePublicStatics.put("NUMERIC", new Integer(2)); + thePublicStatics.put("DOUBLE", new Integer(8)); + thePublicStatics.put("REAL", new Integer(7)); + thePublicStatics.put("FLOAT", new Integer(6)); + thePublicStatics.put("BIGINT", new Integer(-5)); + thePublicStatics.put("INTEGER", new Integer(4)); + thePublicStatics.put("SMALLINT", new Integer(5)); + thePublicStatics.put("TINYINT", new Integer(-6)); + thePublicStatics.put("BIT", new Integer(-7)); + + Class<?> typesClass; + try { + typesClass = Class.forName("java.sql.Types"); + } catch (ClassNotFoundException e) { + fail("java.sql.Types class not found!"); + return; + } // end try + + Field[] theFields = typesClass.getDeclaredFields(); + int requiredModifier = Modifier.PUBLIC + Modifier.STATIC + + Modifier.FINAL; + + int countPublicStatics = 0; + for (Field element : theFields) { + String fieldName = element.getName(); + int theMods = element.getModifiers(); + if (Modifier.isPublic(theMods) && Modifier.isStatic(theMods)) { + try { + Object fieldValue = element.get(null); + Object expectedValue = thePublicStatics.get(fieldName); + if (expectedValue == null) { + fail("Field " + fieldName + " missing!"); + } // end + assertEquals("Field " + fieldName + " value mismatch: ", + expectedValue, fieldValue); + assertEquals("Field " + fieldName + " modifier mismatch: ", + requiredModifier, theMods); + countPublicStatics++; + } catch (IllegalAccessException e) { + fail("Illegal access to Field " + fieldName); + } // end try + } // end if + } // end for + + } // end method testPublicStatics + +} // end class TypesTest diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/AllTests.java b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/AllTests.java new file mode 100644 index 0000000..f1553f2 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/AllTests.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.javax.sql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * This is autogenerated source file. Includes tests for package org.apache.harmony.sql.tests.javax.sql; + */ + +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = new TestSuite("All tests for package org.apache.harmony.sql.tests.javax.sql;"); + // $JUnit-BEGIN$ + + suite.addTestSuite(ConnectionEventTest.class); + suite.addTestSuite(RowSetEventTest.class); + + // $JUnit-END$ + return suite; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.java new file mode 100644 index 0000000..a5d7617 --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.javax.sql; + +import java.sql.SQLException; +import javax.sql.ConnectionEvent; +import junit.framework.TestCase; + +public class ConnectionEventTest extends TestCase { + + public void testConstructorConnection() { + try { + new ConnectionEvent(null); + fail("illegal argument exception expected"); + } catch (IllegalArgumentException e) { + } + + Impl_PooledConnection ipc = new Impl_PooledConnection(); + ConnectionEvent ce = new ConnectionEvent(ipc); + assertSame(ipc, ce.getSource()); + assertNull(ce.getSQLException()); + } + + public void testConstructorConnectionSQLException() { + try { + new ConnectionEvent(null, null); + fail("illegal argument exception expected"); + } catch (IllegalArgumentException e) { + } + + Impl_PooledConnection ipc = new Impl_PooledConnection(); + ConnectionEvent ce = new ConnectionEvent(ipc, null); + assertSame(ipc, ce.getSource()); + assertNull(ce.getSQLException()); + + SQLException e = new SQLException(); + ce = new ConnectionEvent(ipc, e); + assertSame(ipc, ce.getSource()); + assertSame(e, ce.getSQLException()); + } +} + diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_PooledConnection.java b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_PooledConnection.java new file mode 100644 index 0000000..d135ced --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_PooledConnection.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.javax.sql; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.ConnectionEventListener; +import javax.sql.PooledConnection; + +class Impl_PooledConnection implements PooledConnection { + public void addConnectionEventListener(ConnectionEventListener theListener) { + } + + public void close() throws SQLException { + } + + public Connection getConnection() throws SQLException { + return null; + } + + public void removeConnectionEventListener(ConnectionEventListener theListener) { + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_RowSet.java b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_RowSet.java new file mode 100644 index 0000000..ace6b9a --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/Impl_RowSet.java @@ -0,0 +1,738 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.javax.sql; + +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.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Map; +import javax.sql.RowSet; +import javax.sql.RowSetListener; + +@SuppressWarnings("deprecation") +class Impl_RowSet implements RowSet { + public void addRowSetListener(RowSetListener theListener) { + } + + public void clearParameters() throws SQLException { + } + + public void execute() throws SQLException { + } + + public String getCommand() { + return null; + } + + public String getDataSourceName() { + return null; + } + + public boolean getEscapeProcessing() throws SQLException { + return false; + } + + public int getMaxFieldSize() throws SQLException { + return 0; + } + + public int getMaxRows() throws SQLException { + return 0; + } + + public String getPassword() { + return null; + } + + public int getQueryTimeout() throws SQLException { + return 0; + } + + public int getTransactionIsolation() { + return 0; + } + + public Map<String, Class<?>> getTypeMap() throws SQLException { + return null; + } + + public String getUrl() throws SQLException { + return null; + } + + public String getUsername() { + return null; + } + + public boolean isReadOnly() { + return false; + } + + public void removeRowSetListener(RowSetListener theListener) { + } + + public void setArray(int parameterIndex, Array theArray) throws SQLException { + } + + public void setAsciiStream(int parameterIndex, InputStream theInputStream, int length) + throws SQLException { + } + + public void setBigDecimal(int parameterIndex, BigDecimal theBigDecimal) throws SQLException { + } + + public void setBinaryStream(int parameterIndex, InputStream theInputStream, int length) + throws SQLException { + } + + public void setBlob(int parameterIndex, Blob theBlob) throws SQLException { + } + + public void setBoolean(int parameterIndex, boolean theBoolean) throws SQLException { + } + + public void setByte(int parameterIndex, byte theByte) throws SQLException { + } + + public void setBytes(int parameterIndex, byte[] theByteArray) throws SQLException { + } + + public void setCharacterStream(int parameterIndex, Reader theReader, int length) + throws SQLException { + } + + public void setClob(int parameterIndex, Clob theClob) throws SQLException { + } + + public void setCommand(String cmd) throws SQLException { + } + + public void setConcurrency(int concurrency) throws SQLException { + } + + public void setDataSourceName(String name) throws SQLException { + } + + public void setDate(int parameterIndex, Date theDate, Calendar theCalendar) + throws SQLException { + } + + public void setDate(int parameterIndex, Date theDate) throws SQLException { + } + + public void setDouble(int parameterIndex, double theDouble) throws SQLException { + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + } + + public void setFloat(int parameterIndex, float theFloat) throws SQLException { + } + + public void setInt(int parameterIndex, int theInteger) throws SQLException { + } + + public void setLong(int parameterIndex, long theLong) throws SQLException { + } + + public void setMaxFieldSize(int max) throws SQLException { + } + + public void setMaxRows(int max) throws SQLException { + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + } + + public void setObject(int parameterIndex, Object theObject, int targetSqlType, int scale) + throws SQLException { + } + + public void setObject(int parameterIndex, Object theObject, int targetSqlType) + throws SQLException { + } + + public void setObject(int parameterIndex, Object theObject) throws SQLException { + } + + public void setPassword(String password) throws SQLException { + } + + public void setQueryTimeout(int seconds) throws SQLException { + } + + public void setReadOnly(boolean readOnly) throws SQLException { + } + + public void setRef(int parameterIndex, Ref theRef) throws SQLException { + } + + public void setShort(int parameterIndex, short theShort) throws SQLException { + } + + public void setString(int parameterIndex, String theString) throws SQLException { + } + + public void setTime(int parameterIndex, Time theTime, Calendar theCalendar) + throws SQLException { + } + + public void setTime(int parameterIndex, Time theTime) throws SQLException { + } + + public void setTimestamp(int parameterIndex, Timestamp theTimestamp, Calendar theCalendar) + throws SQLException { + } + + public void setTimestamp(int parameterIndex, Timestamp theTimestamp) throws SQLException { + } + + public void setTransactionIsolation(int level) throws SQLException { + } + + public void setType(int type) throws SQLException { + } + + public void setTypeMap(Map<String, Class<?>> theTypeMap) throws SQLException { + } + + public void setUrl(String theURL) throws SQLException { + } + + public void setUsername(String theUsername) throws SQLException { + } + + public boolean absolute(int row) throws SQLException { + return false; + } + + public void afterLast() throws SQLException { + } + + public void beforeFirst() throws SQLException { + } + + public void cancelRowUpdates() throws SQLException { + } + + public void clearWarnings() throws SQLException { + } + + public void close() throws SQLException { + } + + public void deleteRow() throws SQLException { + } + + public int findColumn(String columnName) throws SQLException { + return 0; + } + + public boolean first() throws SQLException { + return false; + } + + public Array getArray(int columnIndex) throws SQLException { + return null; + } + + public Array getArray(String colName) throws SQLException { + return null; + } + + public InputStream getAsciiStream(int columnIndex) throws SQLException { + return null; + } + + public InputStream getAsciiStream(String columnName) throws SQLException { + return null; + } + + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { + return null; + } + + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + return null; + } + + public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException { + return null; + } + + public BigDecimal getBigDecimal(String columnName) throws SQLException { + return null; + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException { + return null; + } + + public InputStream getBinaryStream(String columnName) throws SQLException { + return null; + } + + public Blob getBlob(int columnIndex) throws SQLException { + return null; + } + + public Blob getBlob(String columnName) throws SQLException { + return null; + } + + public boolean getBoolean(int columnIndex) throws SQLException { + return false; + } + + public boolean getBoolean(String columnName) throws SQLException { + return false; + } + + public byte getByte(int columnIndex) throws SQLException { + return 0; + } + + public byte getByte(String columnName) throws SQLException { + return 0; + } + + public byte[] getBytes(int columnIndex) throws SQLException { + return null; + } + + public byte[] getBytes(String columnName) throws SQLException { + return null; + } + + public Reader getCharacterStream(int columnIndex) throws SQLException { + return null; + } + + public Reader getCharacterStream(String columnName) throws SQLException { + return null; + } + + public Clob getClob(int columnIndex) throws SQLException { + return null; + } + + public Clob getClob(String colName) throws SQLException { + return null; + } + + public int getConcurrency() throws SQLException { + return 0; + } + + public String getCursorName() throws SQLException { + return null; + } + + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + public Date getDate(int columnIndex) throws SQLException { + return null; + } + + public Date getDate(String columnName, Calendar cal) throws SQLException { + return null; + } + + public Date getDate(String columnName) throws SQLException { + return null; + } + + public double getDouble(int columnIndex) throws SQLException { + return 0; + } + + public double getDouble(String columnName) throws SQLException { + return 0; + } + + public int getFetchDirection() throws SQLException { + return 0; + } + + public int getFetchSize() throws SQLException { + return 0; + } + + public float getFloat(int columnIndex) throws SQLException { + return 0; + } + + public float getFloat(String columnName) throws SQLException { + return 0; + } + + public int getInt(int columnIndex) throws SQLException { + return 0; + } + + public int getInt(String columnName) throws SQLException { + return 0; + } + + public long getLong(int columnIndex) throws SQLException { + return 0; + } + + public long getLong(String columnName) throws SQLException { + return 0; + } + + public ResultSetMetaData getMetaData() throws SQLException { + return null; + } + + public Object getObject(int columnIndex, Map<String, Class<?>> map) throws SQLException { + return null; + } + + public Object getObject(int columnIndex) throws SQLException { + return null; + } + + public Object getObject(String columnName, Map<String, Class<?>> map) throws SQLException { + return null; + } + + public Object getObject(String columnName) throws SQLException { + return null; + } + + public Ref getRef(int columnIndex) throws SQLException { + return null; + } + + public Ref getRef(String colName) throws SQLException { + return null; + } + + public int getRow() throws SQLException { + return 0; + } + + public short getShort(int columnIndex) throws SQLException { + return 0; + } + + public short getShort(String columnName) throws SQLException { + return 0; + } + + public Statement getStatement() throws SQLException { + return null; + } + + public String getString(int columnIndex) throws SQLException { + return null; + } + + public String getString(String columnName) throws SQLException { + return null; + } + + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + public Time getTime(int columnIndex) throws SQLException { + return null; + } + + public Time getTime(String columnName, Calendar cal) throws SQLException { + return null; + } + + public Time getTime(String columnName) throws SQLException { + return null; + } + + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + return null; + } + + public Timestamp getTimestamp(int columnIndex) throws SQLException { + return null; + } + + public Timestamp getTimestamp(String columnName, Calendar cal) throws SQLException { + return null; + } + + public Timestamp getTimestamp(String columnName) throws SQLException { + return null; + } + + public int getType() throws SQLException { + return 0; + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + return null; + } + + public InputStream getUnicodeStream(String columnName) throws SQLException { + return null; + } + + public URL getURL(int columnIndex) throws SQLException { + return null; + } + + public URL getURL(String columnName) throws SQLException { + return null; + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public void insertRow() throws SQLException { + } + + public boolean isAfterLast() throws SQLException { + return false; + } + + public boolean isBeforeFirst() throws SQLException { + return false; + } + + public boolean isFirst() throws SQLException { + return false; + } + + public boolean isLast() throws SQLException { + return false; + } + + public boolean last() throws SQLException { + return false; + } + + public void moveToCurrentRow() throws SQLException { + } + + public void moveToInsertRow() throws SQLException { + } + + public boolean next() throws SQLException { + return false; + } + + public boolean previous() throws SQLException { + return false; + } + + public void refreshRow() throws SQLException { + } + + public boolean relative(int rows) throws SQLException { + return false; + } + + public boolean rowDeleted() throws SQLException { + return false; + } + + public boolean rowInserted() throws SQLException { + return false; + } + + public boolean rowUpdated() throws SQLException { + return false; + } + + public void setFetchDirection(int direction) throws SQLException { + } + + public void setFetchSize(int rows) throws SQLException { + } + + public void updateArray(int columnIndex, Array x) throws SQLException { + } + + public void updateArray(String columnName, Array x) throws SQLException { + } + + public void updateAsciiStream(int columnIndex, InputStream x, int length) + throws SQLException { + } + + public void updateAsciiStream(String columnName, InputStream x, int length) + throws SQLException { + } + + public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + } + + public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException { + } + + public void updateBinaryStream(int columnIndex, InputStream x, int length) + throws SQLException { + } + + public void updateBinaryStream(String columnName, InputStream x, int length) + throws SQLException { + } + + public void updateBlob(int columnIndex, Blob x) throws SQLException { + } + + public void updateBlob(String columnName, Blob x) throws SQLException { + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + } + + public void updateBoolean(String columnName, boolean x) throws SQLException { + } + + public void updateByte(int columnIndex, byte x) throws SQLException { + } + + public void updateByte(String columnName, byte x) throws SQLException { + } + + public void updateBytes(int columnIndex, byte[] x) throws SQLException { + } + + public void updateBytes(String columnName, byte[] x) throws SQLException { + } + + public void updateCharacterStream(int columnIndex, Reader x, int length) + throws SQLException { + } + + public void updateCharacterStream(String columnName, Reader reader, int length) + throws SQLException { + } + + public void updateClob(int columnIndex, Clob x) throws SQLException { + } + + public void updateClob(String columnName, Clob x) throws SQLException { + } + + public void updateDate(int columnIndex, Date x) throws SQLException { + } + + public void updateDate(String columnName, Date x) throws SQLException { + } + + public void updateDouble(int columnIndex, double x) throws SQLException { + } + + public void updateDouble(String columnName, double x) throws SQLException { + } + + public void updateFloat(int columnIndex, float x) throws SQLException { + } + + public void updateFloat(String columnName, float x) throws SQLException { + } + + public void updateInt(int columnIndex, int x) throws SQLException { + } + + public void updateInt(String columnName, int x) throws SQLException { + } + + public void updateLong(int columnIndex, long x) throws SQLException { + } + + public void updateLong(String columnName, long x) throws SQLException { + } + + public void updateNull(int columnIndex) throws SQLException { + } + + public void updateNull(String columnName) throws SQLException { + } + + public void updateObject(int columnIndex, Object x, int scale) throws SQLException { + } + + public void updateObject(int columnIndex, Object x) throws SQLException { + } + + public void updateObject(String columnName, Object x, int scale) throws SQLException { + } + + public void updateObject(String columnName, Object x) throws SQLException { + } + + public void updateRef(int columnIndex, Ref x) throws SQLException { + } + + public void updateRef(String columnName, Ref x) throws SQLException { + } + + public void updateRow() throws SQLException { + } + + public void updateShort(int columnIndex, short x) throws SQLException { + } + + public void updateShort(String columnName, short x) throws SQLException { + } + + public void updateString(int columnIndex, String x) throws SQLException { + } + + public void updateString(String columnName, String x) throws SQLException { + } + + public void updateTime(int columnIndex, Time x) throws SQLException { + } + + public void updateTime(String columnName, Time x) throws SQLException { + } + + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + } + + public void updateTimestamp(String columnName, Timestamp x) throws SQLException { + } + + public boolean wasNull() throws SQLException { + return false; + } +} diff --git a/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/RowSetEventTest.java b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/RowSetEventTest.java new file mode 100644 index 0000000..e78280b --- /dev/null +++ b/sql/src/test/java/org/apache/harmony/sql/tests/javax/sql/RowSetEventTest.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.sql.tests.javax.sql; + +import javax.sql.RowSetEvent; +import junit.framework.TestCase; + +public class RowSetEventTest extends TestCase { + + public void testConstructor() { + try { + new RowSetEvent(null); + fail("illegal argument exception expected"); + } catch (IllegalArgumentException e) { + } + + Impl_RowSet irs = new Impl_RowSet(); + RowSetEvent rse = new RowSetEvent(irs); + assertSame(irs, rse.getSource()); + } +} diff --git a/sql/src/test/java/tests/java/sql/AllTests.java b/sql/src/test/java/tests/java/sql/AllTests.java new file mode 100644 index 0000000..8ee9e9a --- /dev/null +++ b/sql/src/test/java/tests/java/sql/AllTests.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * This is autogenerated source file. Includes tests for package tests.java.sql; + */ + +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = new TestSuite("All tests for package tests.java.sql;"); + // $JUnit-BEGIN$ + + suite.addTest(DatabaseMetaDataTest.suite()); + suite.addTest(MultiThreadAccessTest.suite()); + suite.addTest(StressTest.suite()); + suite.addTest(UpdateFunctionalityTest.suite()); + suite.addTest(SelectFunctionalityTest.suite()); + suite.addTest(UpdateFunctionalityTest2.suite()); + suite.addTest(DeleteFunctionalityTest.suite()); + suite.addTest(InsertFunctionalityTest.suite()); + + // $JUnit-END$ + return suite; + } +} diff --git a/sql/src/test/java/tests/java/sql/DatabaseMetaDataTest.java b/sql/src/test/java/tests/java/sql/DatabaseMetaDataTest.java new file mode 100755 index 0000000..42ae249 --- /dev/null +++ b/sql/src/test/java/tests/java/sql/DatabaseMetaDataTest.java @@ -0,0 +1,2191 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Arrays; +import java.util.HashSet; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class DatabaseMetaDataTest extends TestCase { + private static String VIEW_NAME = "myView"; + + private static String CREATE_VIEW_QUERY = "CREATE VIEW " + VIEW_NAME + + " AS SELECT * FROM " + DatabaseCreator.TEST_TABLE1; + + private static String DROP_VIEW_QUERY = "DROP VIEW " + VIEW_NAME; + + private static Connection conn; + + private static DatabaseMetaData meta; + + private static Statement statement; + + private static Statement statementForward; + + private static int id = 1; + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + DatabaseMetaDataTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + statementForward = conn.createStatement( + ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_UPDATABLE); + meta = conn.getMetaData(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + statement.close(); + statementForward.close(); + conn.close(); + } + + private void createTestTables() { + try { + ResultSet userTab = meta.getTables(null, null, null, null); + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { + statement.execute(DatabaseCreator.DROP_TABLE1); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE3)) { + statement.execute(DatabaseCreator.DROP_TABLE3); + } else if (tableName.equals(VIEW_NAME)) { + statement.execute(DROP_VIEW_QUERY); + } + } + userTab.close(); + statement.execute(DatabaseCreator.CREATE_TABLE3); + statement.execute(DatabaseCreator.CREATE_TABLE1); + statement.execute(CREATE_VIEW_QUERY); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE1); + statement.execute(DatabaseCreator.DROP_TABLE3); + statement.execute(DROP_VIEW_QUERY); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests java.sql.DatabaseMetaData#allProceduresAreCallable() + */ + public void test_allProceduresAreCallable() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#allTablesAreSelectable() + * + * // TODO GRANT and REVOKE are not supported + */ +/* public void test_allTablesAreSelectable() throws SQLException { + // grant SELECT privileges + + String query = "GRANT CREATE, SELECT ON " + DatabaseCreator.TEST_TABLE1 + + " TO " + Support_SQL.sqlUser; + statement.execute(query); + Connection userConn = Support_SQL.getConnection(Support_SQL.sqlUrl, + Support_SQL.sqlUser, Support_SQL.sqlUser); + DatabaseMetaData userMeta = userConn.getMetaData(); + ResultSet userTab = userMeta.getTables(null, null, null, null); + + assertTrue("Tables are not obtained", userTab.next()); + assertEquals("Incorrect name of obtained table", + DatabaseCreator.TEST_TABLE1.toLowerCase(), userTab.getString( + "TABLE_NAME").toLowerCase()); + assertTrue("Not all of obtained tables are selectable", userMeta + .allTablesAreSelectable()); + + userTab.close(); + // revoke SELECT privileges + query = "REVOKE SELECT ON " + DatabaseCreator.TEST_TABLE1 + " FROM " + + Support_SQL.sqlUser; + statement.execute(query); + + userTab = userMeta.getTables(null, null, null, null); + + assertTrue("Tables are not obtained", userTab.next()); + assertEquals("Incorrect name of obtained table", + DatabaseCreator.TEST_TABLE1.toLowerCase(), userTab.getString( + "TABLE_NAME").toLowerCase()); + assertFalse("No SELECT privileges", userMeta.allTablesAreSelectable()); + + userTab.close(); + // revoke CREATE privileges + query = "REVOKE CREATE ON " + DatabaseCreator.TEST_TABLE1 + " FROM " + + Support_SQL.sqlUser; + statement.execute(query); + userConn.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit() + */ + public void test_dataDefinitionCausesTransactionCommit() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#dataDefinitionIgnoredInTransactions() + */ + public void test_dataDefinitionIgnoredInTransactions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#deletesAreDetected(int) + */ + public void test_deletesAreDetectedI() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#doesMaxRowSizeIncludeBlobs() + */ + public void test_doesMaxRowSizeIncludeBlobs() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData #getAttributes(java.lang.String, + * java.lang.String, java.lang.String, java.lang.String) + */ + public void test_getAttributesLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData #getBestRowIdentifier(java.lang.String, + * java.lang.String, java.lang.String, int, boolean) + */ + public void test_getBestRowIdentifierLjava_lang_StringLjava_lang_StringLjava_lang_StringIZ() + throws SQLException { + ResultSet result = statementForward.executeQuery("SELECT * FROM " + + DatabaseCreator.TEST_TABLE1); + + // TODO not supported +// try { +// result.moveToInsertRow(); +// result.updateInt("id", 1234567); +// result.updateString("field1", "test1"); +// result.insertRow(); +// } catch (SQLException e) { +// fail("Unexpected SQLException " + e.toString()); +// } + + result.close(); + + ResultSet rs = meta.getBestRowIdentifier(null, null, + DatabaseCreator.TEST_TABLE1, DatabaseMetaData.bestRowSession, + true); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 8, col); + String[] columnNames = { "SCOPE", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", + "PSEUDO_COLUMN" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } + assertEquals("Incorrect scope", DatabaseMetaData.bestRowSession, rs + .getShort("SCOPE")); +// assertEquals("Incorrect column name", "id", rs.getString("COLUMN_NAME")); + assertEquals("Incorrect data type", java.sql.Types.INTEGER, rs + .getInt("DATA_TYPE")); + assertEquals("Incorrect type name", "INTEGER", rs.getString("TYPE_NAME")); + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#getCatalogSeparator() + */ + public void test_getCatalogSeparator() throws SQLException { + assertTrue("Incorrect catalog separator", "".equals(meta + .getCatalogSeparator().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getCatalogTerm() + */ + public void test_getCatalogTerm() throws SQLException { + assertTrue("Incorrect catalog term", "".equals(meta + .getCatalogSeparator().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getCatalogs() + */ + public void test_getCatalogs() throws SQLException { + ResultSet rs = meta.getCatalogs(); + // TODO getCatalog is not supported +// while (rs.next()) { + //if (rs.getString("TABLE_CAT").equalsIgnoreCase(conn.getCatalog())) { + // rs.close(); + // return; + //} +// } + rs.close(); +// fail("Incorrect a set of catalogs"); + } + + /** + * @tests java.sql.DatabaseMetaData #getColumnPrivileges(java.lang.String, + * java.lang.String, java.lang.String, java.lang.String) + * + * TODO GRANT is not supported + */ +/* public void test_getColumnPrivilegesLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + ResultSet rs = meta.getColumnPrivileges(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1, "id"); + ResultSetMetaData rsmd = rs.getMetaData(); + assertFalse("Rows are obtained", rs.next()); + rs.close(); + + String query = "GRANT REFERENCES(id) ON " + DatabaseCreator.TEST_TABLE1 + + " TO " + Support_SQL.sqlLogin; + statement.execute(query); + + rs = meta.getColumnPrivileges(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1, "id"); + rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 8, col); + String[] columnNames = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "GRANTOR", "GRANTEE", "PRIVILEGE", + "IS_GRANTABLE" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } + assertEquals("Incorrect table catalogue", conn.getCatalog(), rs + .getString("TABLE_CAT").toLowerCase()); + assertEquals("Incorrect table schema", null, rs + .getString("TABLE_SCHEM")); + assertEquals("Incorrect table name", DatabaseCreator.TEST_TABLE1, rs + .getString("TABLE_NAME").toLowerCase()); + assertEquals("Incorrect column name", "id", rs.getString("COLUMN_NAME") + .toLowerCase()); + assertEquals("Incorrect grantor", Support_SQL.sqlLogin + "@" + + Support_SQL.sqlHost, rs.getString("GRANTOR").toLowerCase()); + assertTrue("Incorrect grantee", + rs.getString("GRANTEE").indexOf("root") != -1); + assertEquals("Incorrect privilege", "references", rs.getString( + "PRIVILEGE").toLowerCase()); + + query = "REVOKE REFERENCES(id) ON " + DatabaseCreator.TEST_TABLE1 + + " FROM " + Support_SQL.sqlLogin; + statement.execute(query); + rs.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#getConnection() + */ + public void test_getConnection() throws SQLException { + assertEquals("Incorrect connection value", conn, meta.getConnection()); + } + + /** + * @tests java.sql.DatabaseMetaData #getCrossReference(java.lang.String, + * java.lang.String, java.lang.String, java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getCrossReferenceLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + ResultSet rs = meta.getCrossReference(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE3, conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 14, col); + String[] columnNames = { "PKTABLE_CAT", "PKTABLE_SCHEM", + "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", + "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", "PK_NAME", + "DEFERRABILITY" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } +// TODO getCatalog is not supported +// assertEquals("Incorrect primary key table catalog", conn.getCatalog(), +// rs.getString("PKTABLE_CAT")); + assertEquals("Incorrect primary key table schema", "", rs + .getString("PKTABLE_SCHEM")); + assertEquals("Incorrect primary key table name", + DatabaseCreator.TEST_TABLE3, rs.getString("PKTABLE_NAME")); + assertEquals("Incorrect primary key column name", "fkey", rs + .getString("PKCOLUMN_NAME")); + // TODO getCatalog is not supported +// assertEquals("Incorrect foreign key table catalog", conn.getCatalog(), +// rs.getString("FKTABLE_CAT")); + assertEquals("Incorrect foreign key table schema", "", rs + .getString("FKTABLE_SCHEM")); + assertEquals("Incorrect foreign key table name", + DatabaseCreator.TEST_TABLE1, rs.getString("FKTABLE_NAME")); + assertEquals("Incorrect foreign key column name", "fk", rs + .getString("FKCOLUMN_NAME")); + assertEquals("Incorrect sequence number within foreign key", 1, rs + .getShort("KEY_SEQ")); + assertEquals("Incorrect update rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("UPDATE_RULE")); + assertEquals("Incorrect delete rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("DELETE_RULE")); + assertNull("Incorrect foreign key name", rs.getString("FK_NAME")); + assertNull("Incorrect primary key name", rs.getString("PK_NAME")); + assertEquals("Incorrect deferrability", + DatabaseMetaData.importedKeyNotDeferrable, rs + .getShort("DEFERRABILITY")); + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#getDatabaseMajorVersion() + */ + public void test_getDatabaseMajorVersion() throws SQLException { + assertTrue("Incorrdct database major version", meta + .getDatabaseMajorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getDatabaseMinorVersion() + */ + public void test_getDatabaseMinorVersion() throws SQLException { + assertTrue("Incorrect database minor version", meta + .getDatabaseMinorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getDatabaseProductName() + */ + public void test_getDatabaseProductName() throws SQLException { + assertTrue("Incorrect database product name", !"".equals(meta + .getDatabaseProductName().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getDatabaseProductVersion() + */ + public void test_getDatabaseProductVersion() throws SQLException { + assertTrue("Incorrect database product version", !"".equals(meta + .getDatabaseProductVersion().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getDefaultTransactionIsolation() + */ + public void test_getDefaultTransactionIsolation() throws SQLException { + int defaultLevel = meta.getDefaultTransactionIsolation(); + switch (defaultLevel) { + case Connection.TRANSACTION_NONE: + case Connection.TRANSACTION_READ_COMMITTED: + case Connection.TRANSACTION_READ_UNCOMMITTED: + case Connection.TRANSACTION_REPEATABLE_READ: + case Connection.TRANSACTION_SERIALIZABLE: + // these levels are OK + break; + default: + fail("Incorrect value of default transaction isolation level"); + } + } + + /** + * @tests java.sql.DatabaseMetaData#getDriverMajorVersion() + */ + public void test_getDriverMajorVersion() { + assertTrue("Incorrect driver major version", meta + .getDriverMajorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getDriverMinorVersion() + */ + public void test_getDriverMinorVersion() { + assertTrue("Incorrect driver minor version", meta + .getDriverMinorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getDriverName() + */ + public void test_getDriverName() throws SQLException { + assertTrue("Incorrect driver name", !"".equals(meta.getDriverName() + .trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getDriverVersion() + */ + public void test_getDriverVersion() throws SQLException { + assertTrue("Incorrect driver version", !"".equals(meta + .getDriverVersion().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData #getExportedKeys(java.lang.String, + * java.lang.String, java.lang.String) + * + * TODO getCatalog is not supported + */ +/* public void test_getExportedKeysLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + ResultSet rs = meta.getExportedKeys(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE3); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 14, col); + String[] columnNames = { "PKTABLE_CAT", "PKTABLE_SCHEM", + "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", + "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", "PK_NAME", + "DEFERRABILITY" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } + + assertEquals("Incorrect primary key table catalog", conn.getCatalog(), + rs.getString("PKTABLE_CAT")); + assertEquals("Incorrect primary key table schema", null, rs + .getString("PKTABLE_SCHEM")); + assertEquals("Incorrect primary key table name", + DatabaseCreator.TEST_TABLE3, rs.getString("PKTABLE_NAME")); + assertEquals("Incorrect primary key column name", "fk", rs + .getString("PKCOLUMN_NAME")); + assertEquals("Incorrect foreign key table catalog", conn.getCatalog(), + rs.getString("FKTABLE_CAT")); + assertEquals("Incorrect foreign key table schema", null, rs + .getString("FKTABLE_SCHEM")); + assertEquals("Incorrect foreign key table name", + DatabaseCreator.TEST_TABLE1, rs.getString("FKTABLE_NAME")); + assertEquals("Incorrect foreign key column name", "fkey", rs + .getString("FKCOLUMN_NAME")); + assertEquals("Incorrect sequence number within foreign key", 1, rs + .getShort("KEY_SEQ")); + assertEquals("Incorrect update rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("UPDATE_RULE")); + assertEquals("Incorrect delete rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("DELETE_RULE")); + assertNotNull("Incorrect foreign key name", rs.getString("FK_NAME")); + assertEquals("Incorrect primary key name", null, rs + .getString("PK_NAME")); + assertEquals("Incorrect deferrability", + DatabaseMetaData.importedKeyNotDeferrable, rs + .getShort("DEFERRABILITY")); + rs.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#getExtraNameCharacters() + */ + public void test_getExtraNameCharacters() throws SQLException { + assertNotNull("Incorrect extra name characters", meta + .getExtraNameCharacters()); + } + + /** + * @tests java.sql.DatabaseMetaData#getIdentifierQuoteString() + */ + public void test_getIdentifierQuoteString() throws SQLException { + assertTrue("Incorrect identifier of quoted string", !"".equals(meta + .getIdentifierQuoteString().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData #getImportedKeys(java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getImportedKeysLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + ResultSet rs = meta.getImportedKeys(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 14, col); + String[] columnNames = { "PKTABLE_CAT", "PKTABLE_SCHEM", + "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", + "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", "PK_NAME", + "DEFERRABILITY" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } +// TODO getCatalog is not supported +// assertEquals("Incorrect primary key table catalog", conn.getCatalog(), +// rs.getString("PKTABLE_CAT")); + assertEquals("Incorrect primary key table schema", "", rs + .getString("PKTABLE_SCHEM")); + assertEquals("Incorrect primary key table name", + DatabaseCreator.TEST_TABLE3, rs.getString("PKTABLE_NAME")); + assertEquals("Incorrect primary key column name", "fkey", rs + .getString("PKCOLUMN_NAME")); +// assertEquals("Incorrect foreign key table catalog", conn.getCatalog(), +// rs.getString("FKTABLE_CAT")); + assertEquals("Incorrect foreign key table schema", "", rs + .getString("FKTABLE_SCHEM")); + assertEquals("Incorrect foreign key table name", + DatabaseCreator.TEST_TABLE1, rs.getString("FKTABLE_NAME")); + assertEquals("Incorrect foreign key column name", "fk", rs + .getString("FKCOLUMN_NAME")); + assertEquals("Incorrect sequence number within foreign key", 1, rs + .getShort("KEY_SEQ")); + assertEquals("Incorrect update rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("UPDATE_RULE")); + assertEquals("Incorrect delete rule value", + DatabaseMetaData.importedKeyNoAction, rs + .getShort("DELETE_RULE")); + // assertNotNull("Incorrect foreign key name", rs.getString("FK_NAME")); + assertEquals("Incorrect primary key name", null, rs + .getString("PK_NAME")); + assertEquals("Incorrect deferrability", + DatabaseMetaData.importedKeyNotDeferrable, rs + .getShort("DEFERRABILITY")); + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData #getIndexInfo(java.lang.String, + * java.lang.String, java.lang.String, boolean, boolean) + * + * TODO getCatalog is not supported + */ +/* public void test_getIndexInfoLjava_lang_StringLjava_lang_StringLjava_lang_StringZZ() + throws SQLException { + boolean unique = false; + ResultSet rs = meta.getIndexInfo(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1, unique, true); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 13, col); + String[] columnNames = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", "TYPE", + "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", + "CARDINALITY", "PAGES", "FILTER_CONDITION" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } + + assertEquals("Incorrect table catalog", conn.getCatalog(), rs + .getString("TABLE_CAT")); + assertEquals("Incorrect table schema", null, rs + .getString("TABLE_SCHEM")); + assertEquals("Incorrect table name", DatabaseCreator.TEST_TABLE1, rs + .getString("TABLE_NAME")); + assertEquals("Incorrect state of uniquess", unique, rs + .getBoolean("NON_UNIQUE")); + assertEquals("Incorrect index catalog", "", rs + .getString("INDEX_QUALIFIER")); + assertEquals("Incorrect index name", "primary", rs.getString( + "INDEX_NAME").toLowerCase()); + assertEquals("Incorrect index type", DatabaseMetaData.tableIndexOther, + rs.getShort("TYPE")); + assertEquals("Incorrect column sequence number within index", 1, rs + .getShort("ORDINAL_POSITION")); + assertEquals("Incorrect column name", "id", rs.getString("COLUMN_NAME")); + assertEquals("Incorrect column sort sequence", "a", rs.getString( + "ASC_OR_DESC").toLowerCase()); + assertEquals("Incorrect cardinality", 1, rs.getInt("CARDINALITY")); + assertEquals("Incorrect value of pages", 0, rs.getInt("PAGES")); + assertEquals("Incorrect filter condition", null, rs + .getString("FILTER_CONDITION")); + rs.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#getJDBCMajorVersion() + */ + public void test_getJDBCMajorVersion() throws SQLException { + assertTrue("Incorrect JDBC major version", + meta.getJDBCMajorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getJDBCMinorVersion() + */ + public void test_getJDBCMinorVersion() throws SQLException { + assertTrue("Incorrect JDBC minor version", + meta.getJDBCMinorVersion() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxBinaryLiteralLength() + */ + public void test_getMaxBinaryLiteralLength() throws SQLException { + assertTrue("Incorrect binary literal length", meta + .getMaxBinaryLiteralLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxCatalogNameLength() + */ + public void test_getMaxCatalogNameLength() throws SQLException { + assertTrue("Incorrect name length", meta.getMaxCatalogNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxCharLiteralLength() + */ + public void test_getMaxCharLiteralLength() throws SQLException { + assertTrue("Incorrect char literal length", meta + .getMaxCharLiteralLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnNameLength() + */ + public void test_getMaxColumnNameLength() throws SQLException { + assertTrue("Incorrect column name length", meta + .getMaxColumnNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnsInGroupBy() + */ + public void test_getMaxColumnsInGroupBy() throws SQLException { + assertTrue("Incorrect number of columns", + meta.getMaxColumnsInGroupBy() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnsInIndex() + */ + public void test_getMaxColumnsInIndex() throws SQLException { + assertTrue("Incorrect number of columns", + meta.getMaxColumnsInIndex() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnsInOrderBy() + */ + public void test_getMaxColumnsInOrderBy() throws SQLException { + assertTrue("Incorrect number of columns", + meta.getMaxColumnsInOrderBy() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnsInSelect() + */ + public void test_getMaxColumnsInSelect() throws SQLException { + assertTrue("Incorrect number of columns", + meta.getMaxColumnsInSelect() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxColumnsInTable() + */ + public void test_getMaxColumnsInTable() throws SQLException { + assertTrue("Incorrect number of columns", + meta.getMaxColumnsInTable() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxConnections() + */ + public void test_getMaxConnections() throws SQLException { + assertTrue("Incorrect number of connections", + meta.getMaxConnections() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxCursorNameLength() + */ + public void test_getMaxCursorNameLength() throws SQLException { + int nameLength = meta.getMaxCursorNameLength(); + if (nameLength > 0) { + try { + statement.setCursorName(new String(new byte[nameLength + 1])); + fail("Expected SQLException was not thrown"); + } catch (SQLException e) { + // expected + } + } else if (nameLength < 0) { + fail("Incorrect length of cursor name"); + } + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxIndexLength() + */ + public void test_getMaxIndexLength() throws SQLException { + assertTrue("Incorrect length of index", meta.getMaxIndexLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxProcedureNameLength() + */ + public void test_getMaxProcedureNameLength() throws SQLException { + assertTrue("Incorrect length of procedure name", meta + .getMaxProcedureNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxRowSize() + */ + public void test_getMaxRowSize() throws SQLException { + assertTrue("Incorrect size of row", meta.getMaxRowSize() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxSchemaNameLength() + */ + public void test_getMaxSchemaNameLength() throws SQLException { + assertTrue("Incorrect length of schema name", meta + .getMaxSchemaNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxStatementLength() + */ + public void test_getMaxStatementLength() throws SQLException { + assertTrue("Incorrect length of statement", meta + .getMaxStatementLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxStatements() + */ + public void test_getMaxStatements() throws SQLException { + assertTrue("Incorrect number of statements", + meta.getMaxStatements() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxTableNameLength() + */ + public void test_getMaxTableNameLength() throws SQLException { + assertTrue("Incorrect length of table name", meta + .getMaxTableNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxTablesInSelect() + */ + public void test_getMaxTablesInSelect() throws SQLException { + assertTrue("Incorrect number of tables", + meta.getMaxTablesInSelect() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getMaxUserNameLength() + */ + public void test_getMaxUserNameLength() throws SQLException { + assertTrue("Incorrect length of user name", + meta.getMaxUserNameLength() >= 0); + } + + /** + * @tests java.sql.DatabaseMetaData#getNumericFunctions() + */ + public void test_getNumericFunctions() throws SQLException { + assertTrue("Incorrect list of math functions", "".equals(meta + .getNumericFunctions().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData #getPrimaryKeys(java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getPrimaryKeysLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + ResultSet rs = meta.getPrimaryKeys(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 6, col); + String[] columnNames = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "COLUMN_NAME", "KEY_SEQ", "PK_NAME" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } +// assertEquals("Incorrect table catalogue", conn.getCatalog(), rs +// .getString("TABLE_CAT").toLowerCase()); + assertEquals("Incorrect table schema", "", rs + .getString("TABLE_SCHEM")); + assertEquals("Incorrect table name", DatabaseCreator.TEST_TABLE1, rs + .getString("TABLE_NAME").toLowerCase()); + assertEquals("Incorrect column name", "id", rs.getString("COLUMN_NAME") + .toLowerCase()); + assertEquals("Incorrect sequence number", 1, rs.getShort("KEY_SEQ")); + // assertEquals("Incorrect primary key name", "primary", rs.getString( + // "PK_NAME").toLowerCase()); + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData #getProcedureColumns(java.lang.String, + * java.lang.String, java.lang.String, java.lang.String) + */ + public void test_getProcedureColumnsLjava_lang_StringLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#getProcedureTerm() + */ + public void test_getProcedureTerm() throws SQLException { + assertTrue("Incorrect procedure term", "".equals(meta + .getProcedureTerm().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData #getProcedures(java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getProceduresLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#getResultSetHoldability() + */ + public void test_getResultSetHoldability() throws SQLException { + int hdb = meta.getResultSetHoldability(); + switch (hdb) { + case ResultSet.HOLD_CURSORS_OVER_COMMIT: + case ResultSet.CLOSE_CURSORS_AT_COMMIT: + // these holdabilities are OK + break; + default: + fail("Incorrect value of holdability"); + } + assertFalse("Incorrect result set holdability", meta + .supportsResultSetHoldability(hdb)); + } + + /** + * @tests java.sql.DatabaseMetaData#getSQLKeywords() + */ + public void test_getSQLKeywords() throws SQLException { + assertTrue("Incorrect SQL keywords", !"".equals(meta.getSQLKeywords() + .trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getSQLStateType() + */ + public void test_getSQLStateType() throws SQLException { + int type = meta.getSQLStateType(); + switch (type) { + case DatabaseMetaData.sqlStateSQL99: + case DatabaseMetaData.sqlStateXOpen: + // these types are OK + break; + default: + fail("Incorrect SQL state types"); + } + } + + /** + * @tests java.sql.DatabaseMetaData#getSchemaTerm() + */ + public void test_getSchemaTerm() throws SQLException { + assertNotNull("Incorrect schema term", meta.getSchemaTerm()); + } + + /** + * @tests java.sql.DatabaseMetaData#getSchemas() + */ + public void test_getSchemas() throws SQLException { + ResultSet rs = meta.getSchemas(); + ResultSetMetaData rsmd = rs.getMetaData(); + assertTrue("Rows do not obtained", rs.next()); + int col = rsmd.getColumnCount(); + assertEquals("Incorrect number of columns", 1, col); + String[] columnNames = { "TABLE_SCHEM", "TABLE_CATALOG" }; + for (int c = 1; c <= col; ++c) { + assertEquals("Incorrect column name", columnNames[c - 1], rsmd + .getColumnName(c)); + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#getSearchStringEscape() + */ + public void test_getSearchStringEscape() throws SQLException { + assertTrue("Incorrect search string escape", !"".equals(meta + .getSearchStringEscape().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData#getStringFunctions() + */ + public void test_getStringFunctions() throws SQLException { + assertTrue("Incorrect string functions", "".equals(meta + .getStringFunctions().trim())); + } + + /** + * @tests java.sql.DatabaseMetaData #getSuperTables(java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getSuperTablesLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData #getSuperTypes(java.lang.String, + * java.lang.String, java.lang.String) + */ + public void test_getSuperTypesLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#getSystemFunctions() + */ + public void test_getSystemFunctions() throws SQLException { + assertTrue("No system function exist", meta.getSystemFunctions() + .trim().equals("")); + } + + /** + * @tests java.sql.DatabaseMetaData #getTablePrivileges(java.lang.String, + * java.lang.String, java.lang.String) + * + * TODO GRANT is not supported + */ +/* public void test_getTablePrivilegesLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + // case 1. Get privileges when no privilegies exist for one table + ResultSet privileges = meta.getTablePrivileges(conn.getCatalog(), "%", + DatabaseCreator.TEST_TABLE3); + assertFalse("Some privilegies exist", privileges.next()); + privileges.close(); + + // case 2. Get privileges when no privilegies exist for all tables + privileges = meta.getTablePrivileges(null, null, null); + assertFalse("Some privilegies exist", privileges.next()); + privileges.close(); + + // case 3. grant CREATE and SELECT privileges ang get them + HashSet<String> expectedPrivs = new HashSet<String>(); + expectedPrivs.add("CREATE"); + expectedPrivs.add("SELECT"); + + String query = "GRANT CREATE, SELECT ON " + DatabaseCreator.TEST_TABLE3 + + " TO " + Support_SQL.sqlUser; + statement.execute(query); + + privileges = meta.getTablePrivileges(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE3); + + while (privileges.next()) { + assertEquals("Wrong catalog name", Support_SQL.sqlCatalog, + privileges.getString("TABLE_CAT")); + assertNull("Wrong schema", privileges.getString("TABLE_SCHEM")); + assertEquals("Wrong table name", DatabaseCreator.TEST_TABLE3, + privileges.getString("TABLE_NAME")); + assertTrue("Wrong privilege " + privileges.getString("PRIVILEGE"), + expectedPrivs.remove(privileges.getString("PRIVILEGE"))); + assertEquals("Wrong grantor", Support_SQL.sqlLogin + "@" + + Support_SQL.sqlHost, privileges.getString("GRANTOR")); + assertEquals("Wrong grantee", Support_SQL.sqlUser + "@%", + privileges.getString("GRANTEE")); + assertNull("Wrong value of IS_GRANTABLE", privileges + .getString("IS_GRANTABLE")); + } + privileges.close(); + assertTrue("Wrong privileges were returned", expectedPrivs.isEmpty()); + + query = "REVOKE CREATE, SELECT ON " + DatabaseCreator.TEST_TABLE3 + + " FROM " + Support_SQL.sqlUser; + statement.execute(query); + + // case 4. grant all privileges ang get them + String[] privs = new String[] { "ALTER", "CREATE", "CREATE VIEW", + "DELETE", "DROP", "INDEX", "INSERT", "REFERENCES", "SELECT", + "SHOW VIEW", "UPDATE" }; + expectedPrivs = new HashSet<String>(); + for (int i = 0; i < privs.length; i++) { + expectedPrivs.add(privs[i]); + } + query = "GRANT ALL ON " + DatabaseCreator.TEST_TABLE3 + " TO " + + Support_SQL.sqlUser; + statement.execute(query); + + privileges = meta.getTablePrivileges(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE3); + + while (privileges.next()) { + assertEquals("Wrong catalog name", Support_SQL.sqlCatalog, + privileges.getString("TABLE_CAT")); + assertNull("Wrong schema", privileges.getString("TABLE_SCHEM")); + assertEquals("Wrong table name", DatabaseCreator.TEST_TABLE3, + privileges.getString("TABLE_NAME")); + assertTrue("Wrong privilege " + privileges.getString("PRIVILEGE"), + expectedPrivs.remove(privileges.getString("PRIVILEGE"))); + assertEquals("Wrong grantor", Support_SQL.sqlLogin + "@" + + Support_SQL.sqlHost, privileges.getString("GRANTOR")); + assertEquals("Wrong grantee", Support_SQL.sqlUser + "@%", + privileges.getString("GRANTEE")); + assertNull("Wrong value of IS_GRANTABLE", privileges + .getString("IS_GRANTABLE")); + } + privileges.close(); + assertTrue("Wrong privileges were returned", expectedPrivs.isEmpty()); + + query = "REVOKE ALL ON " + DatabaseCreator.TEST_TABLE3 + " FROM " + + Support_SQL.sqlUser; + statement.execute(query); + + // case 5. check no privelegies after revoke + privileges = meta.getTablePrivileges(conn.getCatalog(), "%", + DatabaseCreator.TEST_TABLE3); + assertFalse("Some privilegies exist", privileges.next()); + privileges.close(); + + privileges = meta.getTablePrivileges(null, null, null); + assertFalse("Some privilegies exist", privileges.next()); + privileges.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#getTableTypes() + */ + public void test_getTableTypes() throws SQLException { + String[] tableTypes = { "LOCAL TEMPORARY", "TABLE", "VIEW" }; + ResultSet rs = meta.getTableTypes(); + + while (rs.next()) { + assertTrue("Wrong table type", Arrays.binarySearch(tableTypes, rs + .getString("TABLE_TYPE")) > -1); + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData #getTables(java.lang.String, + * java.lang.String, java.lang.String, java.lang.String[]) + */ + public void test_getTablesLjava_lang_StringLjava_lang_StringLjava_lang_String$Ljava_lang_String() + throws SQLException { + String[] tablesName = { VIEW_NAME, DatabaseCreator.TEST_TABLE1, + DatabaseCreator.TEST_TABLE3 }; + String[] tablesType = { "TABLE", "VIEW" }; + + // case 1. get all tables. There are two tables and one view in the + // database + ResultSet rs = meta.getTables(null, null, null, null); + + while (rs.next()) { + assertTrue("Wrong table name", Arrays.binarySearch(tablesName, rs + .getString("TABLE_NAME")) > -1); + // assertNull("Wrong table schema", rs.getString("TABLE_SCHEM")); + assertTrue("Wrong table type", Arrays.binarySearch(tablesType, rs + .getString("TABLE_TYPE")) > -1); + assertEquals("Wrong parameter REMARKS", "", rs.getString("REMARKS")); + } + rs.close(); + + // case 2. get tables with specified types. There are no tables of such + // types + rs = meta.getTables(conn.getCatalog(), null, null, new String[] { + "SYSTEM TABLE", "LOCAL TEMPORARY" }); + assertFalse("Some tables exist", rs.next()); + rs.close(); + + // case 3. get tables with specified types. There is a table of such + // types + rs = meta.getTables(conn.getCatalog(), null, null, new String[] { + "VIEW", "LOCAL TEMPORARY" }); + + assertTrue("No tables exist", rs.next()); + assertEquals("Wrong table name", VIEW_NAME, rs.getString("TABLE_NAME")); +// assertNull("Wrong table schema", rs.getString("TABLE_SCHEM")); + assertEquals("Wrong table type", "VIEW", rs.getString("TABLE_TYPE")); + assertEquals("Wrong parameter REMARKS", "", rs.getString("REMARKS")); + assertFalse("Wrong size of result set", rs.next()); + assertFalse("Some tables exist", rs.next()); + rs.close(); + + // case 4. get all tables using tables pattern. + // There are two tables and one view in the database + rs = meta.getTables(null, null, "%", null); + + while (rs.next()) { + assertTrue("Wrong table name", Arrays.binarySearch(tablesName, rs + .getString("TABLE_NAME")) > -1); +// assertNull("Wrong table schema", rs.getString("TABLE_SCHEM")); + assertTrue("Wrong table type", Arrays.binarySearch(tablesType, rs + .getString("TABLE_TYPE")) > -1); + assertEquals("Wrong parameter REMARKS", "", rs.getString("REMARKS")); + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#getTimeDateFunctions() + */ + public void test_getTimeDateFunctions() throws SQLException { + assertFalse("No time and data functions exist", !meta + .getTimeDateFunctions().trim().equals("")); + } + + /** + * @tests java.sql.DatabaseMetaData#getTypeInfo() + */ + public void test_getTypeInfo() throws SQLException { + insertNewRecord(); + + ResultSet rs = meta.getTypeInfo(); + + final String[] names = { "TYPE_NAME", "DATA_TYPE", "PRECISION", + "LITERAL_PREFIX", "LITERAL_SUFFIX", "CREATE_PARAMS", + "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", + "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE", + "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX" }; + Arrays.sort(names); + + for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) { + assertTrue("wrong column was return", Arrays.binarySearch(names, rs + .getMetaData().getColumnName(i + 1)) > -1); + } + + int[] types = { Types.ARRAY, Types.BIGINT, Types.BINARY, Types.BIT, + Types.BLOB, Types.BOOLEAN, Types.CHAR, Types.CLOB, + Types.DATALINK, Types.DATE, Types.DECIMAL, Types.DISTINCT, + Types.DOUBLE, Types.FLOAT, Types.INTEGER, Types.JAVA_OBJECT, + Types.LONGVARBINARY, Types.LONGVARCHAR, Types.NULL, + Types.NUMERIC, Types.OTHER, Types.REAL, Types.REF, + Types.SMALLINT, Types.STRUCT, Types.TIME, Types.TIMESTAMP, + Types.TINYINT, Types.VARBINARY, Types.VARCHAR }; + Arrays.sort(types); + + while (rs.next()) { + assertTrue("wrong type was return ", Arrays.binarySearch(types, rs + .getInt("DATA_TYPE")) > -1); + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData #getUDTs(java.lang.String, + * java.lang.String, java.lang.String, int[]) + */ + public void test_getUDTsLjava_lang_StringLjava_lang_StringLjava_lang_String$I() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#getURL() + */ + public void test_getURL() throws SQLException { + assertEquals("Wrong url", Support_SQL.sqlUrl, meta.getURL()); + } + + /** + * @tests java.sql.DatabaseMetaData#getUserName() + * + * TODO not supported + */ +/* public void test_getUserName() throws SQLException { + assertEquals("Wrong user name", Support_SQL.sqlLogin + "@" + + Support_SQL.sqlHost, meta.getUserName()); + } +*/ + /** + * @tests java.sql.DatabaseMetaData #getVersionColumns(java.lang.String, + * java.lang.String, java.lang.String) + * + * TODO trigger is not supported + */ +/* public void test_getVersionColumnsLjava_lang_StringLjava_lang_StringLjava_lang_String() + throws SQLException { + insertNewRecord(); + + String triggerName = "updateTrigger"; + String triggerQuery = "CREATE TRIGGER " + triggerName + + " AFTER UPDATE ON " + DatabaseCreator.TEST_TABLE1 + + " FOR EACH ROW BEGIN INSERT INTO " + + DatabaseCreator.TEST_TABLE3 + " SET fk = 10; END;"; + statementForward.execute(triggerQuery); + + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field1='fffff' WHERE id=1"; + statementForward.execute(updateQuery); + + ResultSet rs = meta.getVersionColumns(conn.getCatalog(), null, + DatabaseCreator.TEST_TABLE1); + assertTrue("Result set is empty", rs.next()); + rs.close(); + } +*/ + /** + * @tests java.sql.DatabaseMetaData#insertsAreDetected(int) + */ + public void test_insertsAreDetectedI() throws SQLException { + assertFalse( + "visible row insert can be detected for TYPE_FORWARD_ONLY type", + meta.insertsAreDetected(ResultSet.TYPE_FORWARD_ONLY)); + assertFalse( + "visible row insert can be detected for TYPE_SCROLL_INSENSITIVE type", + meta.insertsAreDetected(ResultSet.TYPE_SCROLL_INSENSITIVE)); + assertFalse( + "visible row insert can be detected for TYPE_SCROLL_SENSITIVE type", + meta.insertsAreDetected(ResultSet.TYPE_SCROLL_SENSITIVE)); + } + + /** + * @tests java.sql.DatabaseMetaData#isCatalogAtStart() + */ + public void test_isCatalogAtStart() throws SQLException { + assertFalse( + "catalog doesn't appear at the start of a fully qualified table name", + meta.isCatalogAtStart()); + } + + /** + * @tests java.sql.DatabaseMetaData#isReadOnly() + */ + public void test_isReadOnly() throws SQLException { + assertFalse("database is not read-only", meta.isReadOnly()); + } + + /** + * @tests java.sql.DatabaseMetaData#locatorsUpdateCopy() + */ + public void test_locatorsUpdateCopy() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#nullPlusNonNullIsNull() + */ + public void test_nullPlusNonNullIsNull() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#nullsAreSortedAtEnd() + */ + public void test_nullsAreSortedAtEnd() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#nullsAreSortedAtStart() + */ + public void test_nullsAreSortedAtStart() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#nullsAreSortedHigh() + */ + public void test_nullsAreSortedHigh() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#nullsAreSortedLow() + */ + public void test_nullsAreSortedLow() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#othersDeletesAreVisible(int) + */ + public void test_othersDeletesAreVisibleI() throws SQLException { + assertFalse( + "deletes made by others are visible for TYPE_FORWARD_ONLY type", + meta.othersDeletesAreVisible(ResultSet.TYPE_FORWARD_ONLY)); + assertFalse( + "deletes made by others are visible for TYPE_SCROLL_INSENSITIVE type", + meta.othersDeletesAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); + assertFalse( + "deletes made by others are visible for TYPE_SCROLL_SENSITIVE type", + meta.othersDeletesAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("deletes made by others are visible for unknown type", meta + .othersDeletesAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#othersInsertsAreVisible(int) + */ + public void test_othersInsertsAreVisibleI() throws SQLException { + assertFalse( + "inserts made by others are visible for TYPE_FORWARD_ONLY type", + meta.othersInsertsAreVisible(ResultSet.TYPE_FORWARD_ONLY)); + assertFalse( + "inserts made by others are visible for TYPE_SCROLL_INSENSITIVE type", + meta.othersInsertsAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); + assertFalse( + "inserts made by others are visible for TYPE_SCROLL_SENSITIVE type", + meta.othersInsertsAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("inserts made by others are visible for unknown type", meta + .othersInsertsAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#othersUpdatesAreVisible(int) + */ + public void test_othersUpdatesAreVisibleI() throws SQLException { + assertFalse( + "updates made by others are visible for TYPE_FORWARD_ONLY type", + meta.othersUpdatesAreVisible(ResultSet.TYPE_FORWARD_ONLY)); + assertFalse( + "updates made by others are visible for TYPE_SCROLL_INSENSITIVE type", + meta.othersUpdatesAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); + assertFalse( + "updates made by others are visible for TYPE_SCROLL_SENSITIVE type", + meta.othersUpdatesAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("updates made by others are visible for unknown type", meta + .othersUpdatesAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#ownDeletesAreVisible(int) + */ + public void test_ownDeletesAreVisibleI() throws SQLException { + // TODO not supported +// assertFalse( +// "result set's own deletes are visible for TYPE_FORWARD_ONLY type", +// meta.ownDeletesAreVisible(ResultSet.TYPE_FORWARD_ONLY)); +// assertFalse( +// "result set's own deletes are visible for TYPE_SCROLL_INSENSITIVE type", +// meta.ownDeletesAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); +// assertFalse( +// "result set's own deletes are visible for TYPE_SCROLL_SENSITIVE type", +// meta.ownDeletesAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("result set's own deletes are visible for unknown type", + meta.ownDeletesAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#ownInsertsAreVisible(int) + */ + public void test_ownInsertsAreVisibleI() throws SQLException { +// assertFalse( +// "result set's own inserts are visible for TYPE_FORWARD_ONLY type", +// meta.ownInsertsAreVisible(ResultSet.TYPE_FORWARD_ONLY)); +// assertFalse( +// "result set's own inserts are visible for TYPE_SCROLL_INSENSITIVE type", +// meta.ownInsertsAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); +// assertFalse( +// "result set's own inserts are visible for TYPE_SCROLL_SENSITIVE type", +// meta.ownInsertsAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("result set's own inserts are visible for unknown type", + meta.ownInsertsAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#ownUpdatesAreVisible(int) + */ + public void test_ownUpdatesAreVisibleI() throws SQLException { + // TODO not supported +// assertFalse( +// "result set's own updates are visible for TYPE_FORWARD_ONLY type", +// meta.ownUpdatesAreVisible(ResultSet.TYPE_FORWARD_ONLY)); +// assertFalse( +// "result set's own updates are visible for TYPE_SCROLL_INSENSITIVE type", +// meta.ownUpdatesAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)); +// assertFalse( +// "result set's own updates are visible for TYPE_SCROLL_SENSITIVE type", +// meta.ownUpdatesAreVisible(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("result set's own updates are visible for unknown type", + meta.ownUpdatesAreVisible(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#storesLowerCaseIdentifiers() + */ + public void test_storesLowerCaseIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#storesLowerCaseQuotedIdentifiers() + */ + public void test_storesLowerCaseQuotedIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#storesMixedCaseIdentifiers() + */ + public void test_storesMixedCaseIdentifiers() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT fieLD1 FROM " + + DatabaseCreator.TEST_TABLE1; + + try { + statement.executeQuery(selectQuery); + if (!meta.storesMixedCaseQuotedIdentifiers()) { + fail("mixed case are supported"); + } + } catch (SQLException e) { + if (meta.storesMixedCaseQuotedIdentifiers()) { + fail("mixed case are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#storesMixedCaseQuotedIdentifiers() + */ + public void test_storesMixedCaseQuotedIdentifiers() throws SQLException { + String quote = meta.getIdentifierQuoteString(); + + insertNewRecord(); + + String selectQuery = "SELECT " + quote + "fieLD1" + quote + " FROM " + + DatabaseCreator.TEST_TABLE1; + + try { + statement.executeQuery(selectQuery); + if (!meta.storesMixedCaseQuotedIdentifiers()) { + fail("mixed case is supported"); + } + } catch (SQLException e) { + if (meta.storesMixedCaseQuotedIdentifiers()) { + fail("mixed case is not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#storesUpperCaseIdentifiers() + */ + public void test_storesUpperCaseIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#storesUpperCaseQuotedIdentifiers() + */ + public void test_storesUpperCaseQuotedIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsANSI92EntryLevelSQL() + */ + public void test_supportsANSI92EntryLevelSQL() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsANSI92FullSQL() + */ + public void test_supportsANSI92FullSQL() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsANSI92IntermediateSQL() + */ + public void test_supportsANSI92IntermediateSQL() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsAlterTableWithAddColumn() + */ + public void test_supportsAlterTableWithAddColumn() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsAlterTableWithDropColumn() + */ + public void test_supportsAlterTableWithDropColumn() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsBatchUpdates() + */ + public void test_supportsBatchUpdates() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCatalogsInDataManipulation() + */ + public void test_supportsCatalogsInDataManipulation() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCatalogsInIndexDefinitions() + */ + public void test_supportsCatalogsInIndexDefinitions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCatalogsInPrivilegeDefinitions() + */ + public void test_supportsCatalogsInPrivilegeDefinitions() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCatalogsInProcedureCalls() + */ + public void test_supportsCatalogsInProcedureCalls() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCatalogsInTableDefinitions() + */ + public void test_supportsCatalogsInTableDefinitions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsColumnAliasing() + */ + public void test_supportsColumnAliasing() throws SQLException { + insertNewRecord(); + + String alias = "FIELD3"; + String selectQuery = "SELECT field1 AS " + alias + " FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet rs = statement.executeQuery(selectQuery); + ResultSetMetaData rsmd = rs.getMetaData(); + + if (meta.supportsColumnAliasing()) { + // supports aliasing + assertEquals("Wrong count of columns", 1, rsmd.getColumnCount()); + assertEquals("Aliasing is not supported", alias, rsmd + .getColumnLabel(1)); + } else { + // doesn't support aliasing + assertEquals("Aliasing is supported", 0, rsmd.getColumnCount()); + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#supportsConvert() + */ + public void test_supportsConvert() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsConvert(int, int) + */ + public void test_supportsConvertII() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCoreSQLGrammar() + */ + public void test_supportsCoreSQLGrammar() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsCorrelatedSubqueries() + */ + public void test_supportsCorrelatedSubqueries() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsDataDefinitionAndDataManipulationTransactions() + */ + public void test_supportsDataDefinitionAndDataManipulationTransactions() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsDataManipulationTransactionsOnly() + */ + public void test_supportsDataManipulationTransactionsOnly() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsDifferentTableCorrelationNames() + */ + public void test_supportsDifferentTableCorrelationNames() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsExpressionsInOrderBy() + */ + public void test_supportsExpressionsInOrderBy() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1 + + " ORDER BY id + field3"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsExpressionsInOrderBy()) { + fail("Expressions in order by are supported"); + } + } catch (SQLException e) { + if (meta.supportsExpressionsInOrderBy()) { + fail("Expressions in order by are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsExtendedSQLGrammar() + */ + public void test_supportsExtendedSQLGrammar() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsFullOuterJoins() + */ + public void test_supportsFullOuterJoins() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsGetGeneratedKeys() + */ + public void test_supportsGetGeneratedKeys() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsGroupBy() + */ + public void test_supportsGroupBy() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1 + + " GROUP BY field3"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsGroupBy()) { + fail("group by are supported"); + } + } catch (SQLException e) { + if (meta.supportsGroupBy()) { + fail("group by are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsGroupByBeyondSelect() + */ + public void test_supportsGroupByBeyondSelect() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsGroupByUnrelated() + */ + public void test_supportsGroupByUnrelated() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT field1, field2 FROM " + + DatabaseCreator.TEST_TABLE1 + " GROUP BY field3"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsGroupByUnrelated()) { + fail("unrelated columns in group by are supported"); + } + } catch (SQLException e) { + if (meta.supportsGroupByUnrelated()) { + fail("unrelated columns in group by are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsIntegrityEnhancementFacility() + */ + public void test_supportsIntegrityEnhancementFacility() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsLikeEscapeClause() + */ + public void test_supportsLikeEscapeClause() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsLimitedOuterJoins() + */ + public void test_supportsLimitedOuterJoins() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMinimumSQLGrammar() + */ + public void test_supportsMinimumSQLGrammar() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMixedCaseIdentifiers() + */ + public void test_supportsMixedCaseIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMixedCaseQuotedIdentifiers() + */ + public void test_supportsMixedCaseQuotedIdentifiers() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMultipleOpenResults() + */ + public void test_supportsMultipleOpenResults() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMultipleResultSets() + */ + public void test_supportsMultipleResultSets() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsMultipleTransactions() + */ + public void test_supportsMultipleTransactions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsNamedParameters() + */ + public void test_supportsNamedParameters() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsNonNullableColumns() + */ + public void test_supportsNonNullableColumns() throws SQLException { + assertTrue( + "columns in this database may not be defined as non-nullable", + meta.supportsNonNullableColumns()); + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOpenCursorsAcrossCommit() + */ + public void test_supportsOpenCursorsAcrossCommit() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOpenCursorsAcrossRollback() + */ + public void test_supportsOpenCursorsAcrossRollback() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOpenStatementsAcrossCommit() + */ + public void test_supportsOpenStatementsAcrossCommit() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOpenStatementsAcrossRollback() + */ + public void test_supportsOpenStatementsAcrossRollback() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOrderByUnrelated() + */ + public void test_supportsOrderByUnrelated() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT field1, field2 FROM " + + DatabaseCreator.TEST_TABLE1 + " ORDER BY id + field3"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsOrderByUnrelated()) { + fail("unrelated columns in order by are supported"); + } + } catch (SQLException e) { + if (meta.supportsOrderByUnrelated()) { + fail("unrelated columns in order by are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsOuterJoins() + */ + public void test_supportsOuterJoins() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsPositionedDelete() + */ + public void test_supportsPositionedDelete() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsPositionedUpdate() + */ + public void test_supportsPositionedUpdate() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsResultSetConcurrency(int, int) + */ + public void test_supportsResultSetConcurrencyII() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsResultSetHoldability(int) + */ + public void test_supportsResultSetHoldabilityI() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsResultSetType(int) + */ + public void test_supportsResultSetTypeI() throws SQLException { + // TODO not supported +// assertFalse("database supports TYPE_FORWARD_ONLY type", meta +// .supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)); +// assertTrue("database doesn't support TYPE_SCROLL_INSENSITIVE type", +// meta.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)); +// assertFalse("database supports TYPE_SCROLL_SENSITIVE type", meta +// .supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("database supports unknown type", meta + .supportsResultSetType(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSavepoints() + */ + public void test_supportsSavepoints() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSchemasInDataManipulation() + */ + public void test_supportsSchemasInDataManipulation() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSchemasInIndexDefinitions() + */ + public void test_supportsSchemasInIndexDefinitions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSchemasInPrivilegeDefinitions() + */ + public void test_supportsSchemasInPrivilegeDefinitions() + throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSchemasInProcedureCalls() + */ + public void test_supportsSchemasInProcedureCalls() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSchemasInTableDefinitions() + */ + public void test_supportsSchemasInTableDefinitions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSelectForUpdate() + */ + public void test_supportsSelectForUpdate() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT field1 FROM " + + DatabaseCreator.TEST_TABLE1 + " FOR UPDATE"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsSelectForUpdate()) { + fail("select for update are supported"); + } + } catch (SQLException e) { + if (!meta.supportsSelectForUpdate()) { + fail("select for update are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsStatementPooling() + */ + public void test_supportsStatementPooling() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsStoredProcedures() + */ + public void test_supportsStoredProcedures() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSubqueriesInComparisons() + */ + public void test_supportsSubqueriesInComparisons() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSubqueriesInExists() + */ + public void test_supportsSubqueriesInExists() throws SQLException { + insertNewRecord(); + + String selectQuery = "SELECT field1 FROM " + + DatabaseCreator.TEST_TABLE1 + + " WHERE EXISTS(SELECT field2 FROM " + + DatabaseCreator.TEST_TABLE1 + ")"; + + try { + statement.executeQuery(selectQuery); + if (!meta.supportsSubqueriesInExists()) { + fail("Subqueries in exists are supported"); + } + } catch (SQLException e) { + if (meta.supportsSubqueriesInExists()) { + fail("Subqueries in exists are not supported"); + } + } + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSubqueriesInIns() + */ + public void test_supportsSubqueriesInIns() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsSubqueriesInQuantifieds() + */ + public void test_supportsSubqueriesInQuantifieds() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsTableCorrelationNames() + */ + public void test_supportsTableCorrelationNames() throws SQLException { + insertNewRecord(); + + String corelationName = "TABLE_NAME"; + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1 + + " AS " + corelationName; + ResultSet rs = statement.executeQuery(selectQuery); + ResultSetMetaData rsmd = rs.getMetaData(); + int numOfColumn = rsmd.getColumnCount(); + + for (int i = 0; i < numOfColumn; i++) { + if (meta.supportsTableCorrelationNames()) { + assertEquals("Corelation names is not supported", + corelationName, rsmd.getTableName(i + 1)); + } else { + assertEquals("Corelation names is supported", + DatabaseCreator.TEST_TABLE1, rsmd.getTableName(i + 1)); + } + } + rs.close(); + } + + /** + * @tests java.sql.DatabaseMetaData#supportsTransactionIsolationLevel(int) + */ + public void test_supportsTransactionIsolationLevelI() throws SQLException { + assertFalse("database supports TRANSACTION_NONE isolation level", meta + .supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE)); + // TODO only Connection.TRANSACTION_SERIALIZABLE is supported +// assertTrue( +// "database doesn't supports TRANSACTION_READ_COMMITTED isolation level", +// meta +// .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)); +// assertTrue( +// "database doesn't supports TRANSACTION_READ_UNCOMMITTED isolation level", +// meta +// .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); +// assertTrue( +// "database doesn't supports TRANSACTION_REPEATABLE_READ isolation level", +// meta +// .supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)); + assertTrue( + "database doesn't supports TRANSACTION_SERIALIZABLE isolation level", + meta + .supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)); + assertFalse("database supports unknown isolation level", meta + .supportsTransactionIsolationLevel(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#supportsTransactions() + */ + public void test_supportsTransactions() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsUnion() + */ + public void test_supportsUnion() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#supportsUnionAll() + */ + public void test_supportsUnionAll() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#updatesAreDetected(int) + */ + public void test_updatesAreDetectedI() throws SQLException { + assertFalse( + "visible row update can be detected for TYPE_FORWARD_ONLY type", + meta.updatesAreDetected(ResultSet.TYPE_FORWARD_ONLY)); + assertFalse( + "visible row update can be detected for TYPE_SCROLL_INSENSITIVE type", + meta.updatesAreDetected(ResultSet.TYPE_SCROLL_INSENSITIVE)); + assertFalse( + "visible row update can be detected for TYPE_SCROLL_SENSITIVE type", + meta.updatesAreDetected(ResultSet.TYPE_SCROLL_SENSITIVE)); + assertFalse("visible row update can be detected for unknown type", meta + .updatesAreDetected(100)); + } + + /** + * @tests java.sql.DatabaseMetaData#usesLocalFilePerTable() + */ + public void test_usesLocalFilePerTable() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + /** + * @tests java.sql.DatabaseMetaData#usesLocalFiles() + */ + public void test_usesLocalFiles() throws SQLException { + // TODO: JDBC does not implement this functionality + } + + private void insertNewRecord() throws SQLException { + String insertQuery = "INSERT INTO " + DatabaseCreator.TEST_TABLE1 + + " (id, field1, field2, field3) VALUES(" + id + ", '" + + "value" + id + "', " + id + ", " + id + ")"; + id++; + statement.execute(insertQuery); + } +} diff --git a/sql/src/test/java/tests/java/sql/DeleteFunctionalityTest.java b/sql/src/test/java/tests/java/sql/DeleteFunctionalityTest.java new file mode 100755 index 0000000..f00a7cf --- /dev/null +++ b/sql/src/test/java/tests/java/sql/DeleteFunctionalityTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class DeleteFunctionalityTest extends TestCase { + + private static Connection conn = null; + + private static Statement statement = null; + + protected void setUp() throws Exception { + super.setUp(); + DatabaseCreator.fillParentTable(conn); + } + + protected void tearDown() throws Exception { + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.FKCASCADE_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.TEST_TABLE5); + super.tearDown(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + DeleteFunctionalityTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + statement.close(); + conn.close(); + } + + private void createTestTables() { + try { + DatabaseMetaData meta = conn.getMetaData(); + ResultSet userTab = meta.getTables(null, null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.PARENT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_PARENT); + } else if (tableName + .equals(DatabaseCreator.FKCASCADE_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + } else if (tableName + .equals(DatabaseCreator.FKSTRICT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE5)) { + statement.execute(DatabaseCreator.DROP_TABLE5); + } + } + userTab.close(); + statement.execute(DatabaseCreator.CREATE_TABLE_PARENT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.CREATE_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.DROP_TABLE_PARENT); + statement.execute(DatabaseCreator.DROP_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests DeleteFunctionalityTest#testDelete1(). Deletes row with no + * referencing ones and RESTRICT action + */ + public void testDelete1() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE + + " WHERE id = 3;"); + } + + /** + * @tests DeleteFunctionalityTest#testDelete2(). Attempts to delete row with + * referencing ones and RESTRICT action - expecting SQLException + * TODO foreign key functionality is not supported + */ +/* public void testDelete2() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + try { + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE + + " WHERE id = 1;"); + fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + } + } +*/ + /** + * @tests DeleteFunctionalityTest#testDelete3(). Deletes all referencing + * rows and then deletes referenced one + */ + public void testDelete3() throws SQLException { + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE + + " WHERE name_id = 1;"); + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE + + " WHERE id = 1;"); + } + + /** + * @tests DeleteFunctionalityTest#testDelete4(). Deletes row with no + * referencing ones and CASCADE action + */ + public void testDelete4() throws SQLException { + DatabaseCreator.fillFKCascadeTable(conn); + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE + + " WHERE id = 3;"); + } + + /** + * @tests DeleteFunctionalityTest#testDelete5(). Attempts to delete row with + * referencing ones and CASCADE action - expecting all referencing + * rows will also be deleted + */ + public void testDelete5() throws SQLException { + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE + + " WHERE id = 1;"); + + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.FKCASCADE_TABLE + " WHERE name_id = 1;"); + r.next(); + assertEquals("Should be no rows", 0, r.getInt(1)); + r.close(); + } + + /** + * @tests DeleteFunctionalityTest#testDelete6(). Deletes rows using subquery + * in WHERE clause + * TODO Foreign key functionality is not supported + */ +/* public void testDelete6() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE + + " WHERE name_id = ANY (SELECT id FROM " + + DatabaseCreator.PARENT_TABLE + " WHERE id > 1)"); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.FKSTRICT_TABLE + " WHERE name_id = 1;"); + r.next(); + assertEquals("Should be 2 rows", 2, r.getInt(1)); + r.close(); + } +*/ + /** + * @tests DeleteFunctionalityTest#testDelete7(). Deletes rows using + * PreparedStatement + */ + public void testDelete7() throws SQLException { + DatabaseCreator.fillTestTable5(conn); + PreparedStatement stat = conn.prepareStatement("DELETE FROM " + + DatabaseCreator.TEST_TABLE5 + " WHERE testID = ?"); + stat.setInt(1, 1); + stat.execute(); + stat.setInt(1, 2); + stat.execute(); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.TEST_TABLE5 + " WHERE testID < 3 "); + r.next(); + assertEquals(0, r.getInt(1)); + r.close(); + stat.close(); + } +} diff --git a/sql/src/test/java/tests/java/sql/InsertFunctionalityTest.java b/sql/src/test/java/tests/java/sql/InsertFunctionalityTest.java new file mode 100755 index 0000000..7ad2d3e --- /dev/null +++ b/sql/src/test/java/tests/java/sql/InsertFunctionalityTest.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import tests.support.Support_SQL; +import tests.support.DatabaseCreator; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class InsertFunctionalityTest extends TestCase { + + private static Connection conn = null; + + private static Statement statement = null; + + protected void setUp() throws Exception { + super.setUp(); + Support_SQL.loadDriver(); + conn = Support_SQL.getConnection(); + + } + + protected void tearDown() throws Exception { + statement.execute("DELETE FROM " + DatabaseCreator.SIMPLE_TABLE2); + statement.execute("DELETE FROM " + DatabaseCreator.SIMPLE_TABLE1); + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.FKCASCADE_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.TEST_TABLE5); + super.tearDown(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + InsertFunctionalityTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + statement.close(); + conn.close(); + } + + private void createTestTables() { + try { + DatabaseMetaData meta = conn.getMetaData(); + ResultSet userTab = meta.getTables(null, null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.PARENT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_PARENT); + } else if (tableName + .equals(DatabaseCreator.FKCASCADE_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + } else if (tableName + .equals(DatabaseCreator.FKSTRICT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + } else if (tableName + .equals(DatabaseCreator.SIMPLE_TABLE1)) { + statement + .execute(DatabaseCreator.DROP_TABLE_SIMPLE1); + } else if (tableName + .equals(DatabaseCreator.SIMPLE_TABLE2)) { + statement + .execute(DatabaseCreator.DROP_TABLE_SIMPLE2); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE5)) { + statement.execute(DatabaseCreator.DROP_TABLE5); + } + } + userTab.close(); + statement.execute(DatabaseCreator.CREATE_TABLE_PARENT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.CREATE_TABLE_SIMPLE2); + statement.execute(DatabaseCreator.CREATE_TABLE_SIMPLE1); + statement.execute(DatabaseCreator.CREATE_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.DROP_TABLE_PARENT); + statement.execute(DatabaseCreator.DROP_TABLE_SIMPLE2); + statement.execute(DatabaseCreator.DROP_TABLE_SIMPLE1); + statement.execute(DatabaseCreator.DROP_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests InsertFunctionalityTest#testInsert1(). Attempts to insert row into + * table with integrity checking + */ + public void testInsert1() throws SQLException { + DatabaseCreator.fillParentTable(conn); + DatabaseCreator.fillFKStrictTable(conn); + DatabaseCreator.fillFKCascadeTable(conn); + statement.execute("INSERT INTO " + DatabaseCreator.FKSTRICT_TABLE + + " VALUES(4, 1, 'testInsert')"); + statement.execute("INSERT INTO " + DatabaseCreator.FKCASCADE_TABLE + + " VALUES(4, 1, 'testInsert')"); + } + + /** + * @tests InsertFunctionalityTest#testInsert2(). Attempts to insert row into + * table with integrity checking when row has incorrect foreign key + * value - expecting SQLException + */ + public void testInsert2() throws SQLException { + DatabaseCreator.fillParentTable(conn); + DatabaseCreator.fillFKStrictTable(conn); + DatabaseCreator.fillFKCascadeTable(conn); + try { + statement.execute("INSERT INTO " + DatabaseCreator.FKSTRICT_TABLE + + " VALUES(4, 4, 'testInsert')"); + // TODO Foreign key functionality isn't supported + // fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + } + try { + statement.execute("INSERT INTO " + DatabaseCreator.FKCASCADE_TABLE + + " VALUES(4, 4, 'testInsert')"); + // TODO Foreign key functionality isn't supported + // fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + } + } + + /** + * @tests InsertFunctionalityTest#testInsert3(). Tests INSERT ... SELECT + * functionality + */ + public void testInsert3() throws SQLException { + DatabaseCreator.fillParentTable(conn); + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("INSERT INTO " + DatabaseCreator.TEST_TABLE5 + + " SELECT id AS testId, value AS testValue " + "FROM " + + DatabaseCreator.FKSTRICT_TABLE + " WHERE name_id = 1"); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.TEST_TABLE5); + r.next(); + assertEquals("Should be 2 rows", 2, r.getInt(1)); + r.close(); + } + + /** + * @tests InsertFunctionalityTest#testInsert4(). Tests INSERT ... SELECT + * with expressions in SELECT query + */ + public void testInsert4() throws SQLException { + DatabaseCreator.fillSimpleTable1(conn); + statement.execute("INSERT INTO " + DatabaseCreator.SIMPLE_TABLE2 + + " SELECT id, speed*10 AS speed, size-1 AS size FROM " + + DatabaseCreator.SIMPLE_TABLE1); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.SIMPLE_TABLE2 + " AS a JOIN " + + DatabaseCreator.SIMPLE_TABLE1 + + " AS b ON a.speed = 10*b.speed AND a.size = b.size-1"); + r.next(); + assertEquals("Should be 2 rows", 2, r.getInt(1)); + r.close(); + } + + /** + * @tests InsertFunctionalityTest#testInsert5(). Inserts multiple rows using + * UNION ALL + */ + public void testInsert5() throws SQLException { + statement.execute("INSERT INTO " + DatabaseCreator.TEST_TABLE5 + + " SELECT 1 as testId, 2 as testValue " + + "UNION SELECT 2 as testId, 3 as testValue " + + "UNION SELECT 3 as testId, 4 as testValue"); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.TEST_TABLE5); + r.next(); + assertEquals("Should be 3 rows", 3, r.getInt(1)); + r.close(); + } + + /** + * @tests InsertFunctionalityTest#testInsert6(). Tests INSERT with + * PreparedStatement + */ + public void testInsertPrepared() throws SQLException { + PreparedStatement stat = conn.prepareStatement("INSERT INTO " + + DatabaseCreator.TEST_TABLE5 + " VALUES(?, ?)"); + stat.setInt(1, 1); + stat.setString(2, "1"); + stat.execute(); + stat.setInt(1, 2); + stat.setString(2, "3"); + stat.execute(); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.TEST_TABLE5 + + " WHERE (testId = 1 AND testValue = '1') " + + "OR (testId = 2 AND testValue = '3')"); + r.next(); + assertEquals("Incorrect number of records", 2, r.getInt(1)); + r.close(); + stat.close(); + } +} diff --git a/sql/src/test/java/tests/java/sql/MultiThreadAccessTest.java b/sql/src/test/java/tests/java/sql/MultiThreadAccessTest.java new file mode 100755 index 0000000..b88aa4e --- /dev/null +++ b/sql/src/test/java/tests/java/sql/MultiThreadAccessTest.java @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import tests.support.ThreadPool; + +public class MultiThreadAccessTest extends TestCase { + + private static Connection conn; + + private static Statement statement; + + private static final int numThreads = 10; + + private static final int numOfRecords = 20; + + private ThreadPool threadPool; + + protected void setUp() throws Exception { + threadPool = new ThreadPool(numThreads); + } + + protected void tearDown() throws Exception { + threadPool.join(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + MultiThreadAccessTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + conn.close(); + statement.close(); + } + + private void createTestTables() { + try { + ResultSet userTab = conn.getMetaData().getTables(null, + null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { + statement.execute(DatabaseCreator.DROP_TABLE1); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE2)) { + statement.execute(DatabaseCreator.DROP_TABLE2); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE4)) { + statement.execute(DatabaseCreator.DROP_TABLE4); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE3)) { + statement.execute(DatabaseCreator.DROP_TABLE3); + } + } + + userTab.close(); + statement.execute(DatabaseCreator.CREATE_TABLE3); + statement.execute(DatabaseCreator.CREATE_TABLE4); + statement.execute(DatabaseCreator.CREATE_TABLE1); + statement.execute(DatabaseCreator.CREATE_TABLE2); + + DatabaseCreator.fillTestTable1(conn, numOfRecords); + DatabaseCreator.fillTestTable2(conn, numOfRecords); + DatabaseCreator.fillTestTable4(conn, numOfRecords); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE1); + statement.execute(DatabaseCreator.DROP_TABLE2); + statement.execute(DatabaseCreator.DROP_TABLE3); + statement.execute(DatabaseCreator.DROP_TABLE4); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * A few threads execute select operation in the same time for one table in + * the database. Number of threads is defined by numThreads variable + * + * @throws SQLException + */ + public void test_MultipleAccessToOneTable() throws SQLException { + for (int i = 0; i < numThreads; i++) { + threadPool.runTask(createTask1(i)); + } + } + + /** + * A few threads execute select operation in the same time for different + * tables in the database. Number of threads is defined by numThreads + * variable + * + * @throws SQLException + */ + public void test_MultipleAccessToSeveralTables() throws SQLException { + threadPool.runTask(createTask1(1)); + threadPool.runTask(createTask2(2)); + threadPool.runTask(createTask3(3)); + } + + /** + * A few threads execute update, insert and delete operations in the same + * time for one table in the database. Number of threads is defined by + * numThreads variable + * + * @throws SQLException + */ + public void test_MultipleOperationsInSeveralTables() throws SQLException { + int id1 = numOfRecords - 1; + threadPool.runTask(createTask4(id1)); + + int id2 = numOfRecords + 1; + threadPool.runTask(createTask5(id2)); + + int oldID = 5; + int newID = 100; + threadPool.runTask(createTask6(oldID, newID)); + + threadPool.join(); + + Statement statement = conn.createStatement(); + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1 + + " WHERE id="; + + ResultSet result = statement.executeQuery(selectQuery + id1); + assertFalse("The record was not deleted", result.next()); + + result = statement.executeQuery(selectQuery + id2); + assertTrue("The record was not inserted", result.next()); + + assertEquals("Wrong value of field1", DatabaseCreator.defaultString + + id2, result.getString("field1")); + // TODO getBigDecimal is not supported +// assertEquals("Wrong value of field2", BigDecimal.valueOf(id2), result +// .getBigDecimal("field2")); +// assertEquals("Wrong value of field3", BigDecimal.valueOf(id2), result +// .getBigDecimal("field3")); + result.close(); + + result = statement.executeQuery(selectQuery + oldID); + assertFalse("The record was not deleted", result.next()); + result.close(); + + result = statement.executeQuery(selectQuery + newID); + assertTrue("The record was not updated", result.next()); + + assertEquals("Wrong value of field1", DatabaseCreator.defaultString + + newID, result.getString("field1")); + // TODO getBigDecimal is not supported +// assertEquals("Wrong value of field2", BigDecimal.valueOf(newID), result +// .getBigDecimal("field2")); +// assertEquals("Wrong value of field3", BigDecimal.valueOf(newID), result +// .getBigDecimal("field3")); + result.close(); + } + + /** + * A few threads execute update operation in the same time for one tables in + * the database. Number of threads is defined by numThreads variable + * + * @throws SQLException + */ + public void test_MultipleUpdatesInOneTables() throws SQLException { + int id = 1; + String field = "field3"; + + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1 + + " WHERE id=" + id; + Statement statement = conn.createStatement(); + + ResultSet result = statement.executeQuery(selectQuery); + assertTrue("There is no records with id = " + id, result.next()); + // TODO getBigDecimal is not supported +// assertEquals("Wrong value of field " + field, BigDecimal.valueOf(id), +// result.getBigDecimal(field)); + result.close(); + + for (int i = 0; i < numThreads; i++) { + threadPool.runTask(createTask7(id, field)); + } + + threadPool.join(); + + double expectedVal = id + numThreads; + result = statement.executeQuery(selectQuery); + assertTrue("There is no records with id = " + id, result.next()); + // TODO getBigDecimal is not supported +// assertEquals("Wrong value of field " + field, expectedVal, result +// .getBigDecimal(field).doubleValue()); + result.close(); + } + + /** + * This method creates a Runnable that executes select operation for the + * first table + * + * @param taskID + * @return + */ + private static Runnable createTask1(final int taskID) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + ResultSet result = statement.executeQuery("SELECT * FROM " + + DatabaseCreator.TEST_TABLE1); + + while (result.next()) { + assertEquals("Wrong value of id ", + DatabaseCreator.defaultString + + result.getInt("id"), result + .getString("field1")); + assertEquals("Wrong value of field2 ", BigDecimal + .valueOf(result.getInt("id")), result + .getBigDecimal("field2")); + assertEquals("Wrong value of field3 ", BigDecimal + .valueOf(result.getInt("id")), result + .getBigDecimal("field3")); + } + result.close(); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that execute select operation for the + * second table + * + * @param taskID + */ + private static Runnable createTask2(final int taskID) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + ResultSet result = statement.executeQuery("SELECT * FROM " + + DatabaseCreator.TEST_TABLE2); + + while (result.next()) { + while (result.next()) { + int id = result.getInt("finteger"); + assertEquals("Wrong value of ftext", + DatabaseCreator.defaultString + id, result + .getString("ftext")); + assertEquals("Wrong value of fcharacter", + DatabaseCreator.defaultCharacter + id, + result.getString("fcharacter")); + assertEquals("Wrong value of fdecimal", + DatabaseCreator.defaultDouble + id, result + .getDouble("fdecimal")); + assertEquals("Wrong value of fnumeric", + DatabaseCreator.defaultDouble + id, result + .getDouble("fnumeric")); + assertEquals("Wrong value of fsmallint", result + .getInt("finteger"), result + .getShort("fsmallint")); + assertEquals("Wrong value of ffloat", + (float) DatabaseCreator.defaultDouble + id, + result.getFloat("ffloat")); + assertEquals("Wrong value of freal", + (float) DatabaseCreator.defaultDouble + id, + result.getFloat("freal")); + assertEquals("Wrong value of fdouble", + DatabaseCreator.defaultDouble + id, result + .getDouble("fdouble")); + } + } + result.close(); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that execute select operation for the + * third table + * + * @param taskID + */ + private static Runnable createTask3(final int taskID) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + ResultSet result = statement.executeQuery("SELECT * FROM " + + DatabaseCreator.TEST_TABLE4); + + while (result.next()) { + assertEquals("Wrong value of field1", + DatabaseCreator.defaultString + + result.getInt("fk"), result + .getString("field1")); + } + result.close(); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that executes delete operation for the + * first table + * + * @param taskID + */ + private static Runnable createTask4(final int id) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + statement.execute("DELETE FROM " + + DatabaseCreator.TEST_TABLE1 + " WHERE id=" + id); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that executes insert operation for the + * first table + * + * @param taskID + */ + private static Runnable createTask5(final int id) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + String value = DatabaseCreator.defaultString + id; + + String insertQuery = "INSERT INTO " + + DatabaseCreator.TEST_TABLE1 + + " (id, field1, field2, field3) VALUES(" + id + + ", '" + value + "', " + id + ", " + id + ")"; + statement.execute(insertQuery); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that executes update operation for the one + * record of the first table + * + * @param taskID + */ + private static Runnable createTask6(final int oldID, final int newID) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + String value = DatabaseCreator.defaultString + newID; + String updateQuery = "UPDATE " + + DatabaseCreator.TEST_TABLE1 + " SET id=" + newID + + ", field1='" + value + "', field2=" + newID + + ", field3=" + newID + " WHERE id=" + oldID; + statement.execute(updateQuery); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } + + /** + * This method creates a Runnable that executes update operation for the one + * field of one record with identifier id in the first table + * + * @param taskID + */ + private static Runnable createTask7(final int id, final String field) { + return new Runnable() { + public void run() { + try { + Statement statement = conn.createStatement(); + String updateQuery = "UPDATE " + + DatabaseCreator.TEST_TABLE1 + " SET " + field + + "= " + field + "+ 1 WHERE id=" + id; + statement.execute(updateQuery); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + } + }; + } +} diff --git a/sql/src/test/java/tests/java/sql/SelectFunctionalityTest.java b/sql/src/test/java/tests/java/sql/SelectFunctionalityTest.java new file mode 100755 index 0000000..a0ded6a --- /dev/null +++ b/sql/src/test/java/tests/java/sql/SelectFunctionalityTest.java @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.io.CharArrayReader; +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.HashSet; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class SelectFunctionalityTest extends TestCase { + + private static Connection conn; + + private static Statement statement; + + private static Date date; + + private static Time time; + + protected void setUp() throws Exception { + super.setUp(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + SelectFunctionalityTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + conn.close(); + statement.close(); + } + + private void createTestTables() { + try { + ResultSet userTab = conn.getMetaData().getTables(null, + null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.TEST_TABLE2)) { + statement.execute(DatabaseCreator.DROP_TABLE2); + } else if (tableName + .equals(DatabaseCreator.SALESPEOPLE_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_SALESPEOPLE); + } else if (tableName + .equals(DatabaseCreator.CUSTOMERS_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_CUSTOMERS); + } else if (tableName + .equals(DatabaseCreator.ORDERS_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_ORDERS); + } + } + userTab.close(); + + statement.execute(DatabaseCreator.CREATE_TABLE2); + statement.execute(DatabaseCreator.CREATE_TABLE_SALESPEOPLE); + statement.execute(DatabaseCreator.CREATE_TABLE_CUSTOMERS); + statement.execute(DatabaseCreator.CREATE_TABLE_ORDERS); + + long currentTime = Calendar.getInstance().getTimeInMillis(); + date = new Date(currentTime); + time = new Time(currentTime); + + DatabaseCreator.fillTestTable2(conn, 1, 5, currentTime); + DatabaseCreator.fillCustomersTable(conn); + DatabaseCreator.fillOrdersTable(conn); + DatabaseCreator.fillSalesPeopleTable(conn); + + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE2); + statement.execute(DatabaseCreator.DROP_TABLE_SALESPEOPLE); + statement.execute(DatabaseCreator.DROP_TABLE_CUSTOMERS); + statement.execute(DatabaseCreator.DROP_TABLE_ORDERS); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests SelectFunctionalityTest#test_SelectSimple(). Selects all records + * from the table + */ + public void test_SelectSimple() throws SQLException { + String sql = "SELECT * FROM " + DatabaseCreator.TEST_TABLE2; + ResultSet result = statement.executeQuery(sql); + int counter = 0; + + while (result.next()) { + int id = result.getInt("finteger"); + assertEquals("expected value doesn't equal actual", + DatabaseCreator.defaultString + id, result + .getString("ftext")); + assertEquals("expected value doesn't equal actual", + DatabaseCreator.defaultCharacter + id, result + .getString("fcharacter")); + + // TODO getBigDecimal is not supported +// assertEquals("expected value doesn't equal actual", BigDecimal +// .valueOf(id + 0.1), result.getBigDecimal("fdecimal")); +// assertEquals("expected value doesn't equal actual", BigDecimal +// .valueOf(id + 0.1), result.getBigDecimal("fnumeric")); +// assertEquals("expected value doesn't equal actual", id, result +// .getInt("fsmallint")); + assertEquals("expected value doesn't equal actual", BigDecimal + .valueOf(id + 0.1).floatValue(), result.getFloat("ffloat")); + assertEquals("expected value doesn't equal actual", BigDecimal + .valueOf(id + 0.1).doubleValue(), result.getDouble("freal")); + assertEquals("expected value doesn't equal actual", BigDecimal + .valueOf(id + 0.1).doubleValue(), result + .getDouble("fdouble")); + assertEquals("expected value doesn't equal actual", + date.toString(), result.getDate("fdate").toString()); + assertEquals("expected value doesn't equal actual", + time.toString(), result.getTime("ftime").toString()); + counter++; + } + + assertEquals("number of rows in ResultSet is wrong", 5, counter); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectPrepared(). Selects all records + * from the table using parametric query + */ + public void test_SelectPrepared() throws SQLException { + String sql = "SELECT finteger, ftext, fcharacter, fdecimal, fnumeric," + + " fsmallint, ffloat, freal, fdouble, fdate, ftime" + " FROM " + + DatabaseCreator.TEST_TABLE2 + + " WHERE finteger = ? AND ftext = ? AND fcharacter = ? AND" + + " fdecimal = ? AND fnumeric = ? AND fsmallint = ? AND" + + " freal = ? AND fdouble = ? AND fdate = ?" + " AND ftime = ?"; + PreparedStatement prepStatement = conn.prepareStatement(sql); + + CharArrayReader reader = new CharArrayReader(new String( + DatabaseCreator.defaultCharacter + "1").toCharArray()); + prepStatement.setInt(1, 1); + prepStatement.setString(2, DatabaseCreator.defaultString + "1"); +// TODO setCharacterStream and setBigDecimal are not supported +// prepStatement.setCharacterStream(3, reader, 4); +// prepStatement.setBigDecimal(4, BigDecimal.valueOf(1.1)); +// prepStatement.setBigDecimal(5, BigDecimal.valueOf(1.1)); + prepStatement.setInt(6, 1); + prepStatement.setDouble(7, 1.1); + prepStatement.setDouble(8, 1.1); + prepStatement.setDate(9, date); + prepStatement.setTime(10, time); + + int counter = 0; + ResultSet result = prepStatement.executeQuery(); + while (result.next()) { + int id = result.getInt("finteger"); + assertEquals("expected value doesn't equal actual", + DatabaseCreator.defaultString + id, result + .getString("ftext")); + assertEquals("expected value doesn't equal actual", + DatabaseCreator.defaultCharacter + id, result + .getString("fcharacter")); +// TODO getBigDecimal is not supported +// assertEquals("expected value doesn't equal actual", BigDecimal +// .valueOf(1.1), result.getBigDecimal("fdecimal")); +// assertEquals("expected value doesn't equal actual", BigDecimal +// .valueOf(1.1), result.getBigDecimal("fnumeric")); + assertEquals("expected value doesn't equal actual", id, result + .getInt("fsmallint")); + assertEquals("expected value doesn't equal actual", + (float) (id + 0.1), result.getFloat("ffloat")); + assertEquals("expected value doesn't equal actual", + (double) (id + 0.1), result.getDouble("freal")); + assertEquals("expected value doesn't equal actual", + (double) (id + 0.1), result.getDouble("fdouble")); + assertEquals("expected value doesn't equal actual", + date.toString(), result.getDate("fdate").toString()); + assertEquals("expected value doesn't equal actual", + time.toString(), result.getTime("ftime").toString()); + counter++; + } +// TODO query wasn't executed due to "not supported" methods +// assertEquals("number of rows in ResultSet is wrong", 1, counter); + prepStatement.close(); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SubSelect(). Selects records from the + * table using subselect + */ + public void test_SubSelect() throws SQLException { + String sql = "SELECT finteger," + " (SELECT ftext FROM " + + DatabaseCreator.TEST_TABLE2 + " WHERE finteger = 1) as ftext" + + " FROM " + DatabaseCreator.TEST_TABLE2; + ResultSet result = statement.executeQuery(sql); + + HashMap<Integer, String> value = new HashMap<Integer, String>(); + value.put(1, DatabaseCreator.defaultString + "1"); + value.put(2, DatabaseCreator.defaultString + "1"); + value.put(3, DatabaseCreator.defaultString + "1"); + value.put(4, DatabaseCreator.defaultString + "1"); + value.put(5, DatabaseCreator.defaultString + "1"); + + while (result.next()) { + int key = result.getInt("finteger"); + String val = result.getString("ftext"); + assertTrue("wrong value of finteger field", value.containsKey(key)); + assertEquals("wrong value of ftext field", value.get(key), val); + value.remove(key); + } + assertTrue("expected rows number doesn't equal actual rows number", + value.isEmpty()); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectThreeTables(). Selects records + * from a few tables + */ + public void test_SelectThreeTables() throws SQLException { + String sql = "SELECT onum, " + DatabaseCreator.ORDERS_TABLE + ".cnum" + + " FROM " + DatabaseCreator.SALESPEOPLE_TABLE + ", " + + DatabaseCreator.CUSTOMERS_TABLE + ", " + + DatabaseCreator.ORDERS_TABLE + " WHERE " + + DatabaseCreator.CUSTOMERS_TABLE + ".city <> " + + DatabaseCreator.SALESPEOPLE_TABLE + ".city" + " AND " + + DatabaseCreator.ORDERS_TABLE + ".cnum = " + + DatabaseCreator.CUSTOMERS_TABLE + ".cnum" + " AND " + + DatabaseCreator.ORDERS_TABLE + ".snum = " + + DatabaseCreator.SALESPEOPLE_TABLE + ".snum"; + ResultSet result = statement.executeQuery(sql); + + HashMap<Integer, Integer> value = new HashMap<Integer, Integer>(); + value.put(3001, 2008); + value.put(3002, 2007); + value.put(3006, 2008); + value.put(3009, 2002); + value.put(3007, 2004); + value.put(3010, 2004); + + while (result.next()) { + int key = result.getInt("onum"); + int val = result.getInt("cnum"); + assertTrue("wrong value of onum field", value.containsKey(key)); + assertEquals("wrong value of cnum field", value.get(key), + (Integer) val); + value.remove(key); + } + assertTrue("expected rows number doesn't equal actual rows number", + value.isEmpty()); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectThreeTables(). Selects records + * from a table using union + */ + public void test_SelectUnionItself() throws SQLException { + String sql = "SELECT b.cnum, b.cname" + " FROM " + + DatabaseCreator.CUSTOMERS_TABLE + " a, " + + DatabaseCreator.CUSTOMERS_TABLE + " b" + + " WHERE a.snum = 1002" + " AND b.city = a.city"; + ResultSet result = statement.executeQuery(sql); + + HashMap<Integer, String> value = new HashMap<Integer, String>(); + value.put(2003, "Liu"); + value.put(2004, "Grass"); + value.put(2008, "Cisneros"); + + while (result.next()) { + int key = result.getInt("cnum"); + String val = result.getString("cname"); + assertTrue("wrong value of cnum field", value.containsKey(key)); + assertEquals("wrong value of cname field", value.get(key), val); + value.remove(key); + } + assertTrue("expected rows number doesn't equal actual rows number", + value.isEmpty()); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectLeftOuterJoin(). Selects + * records from a table using left join + */ + public void test_SelectLeftOuterJoin() throws SQLException { + String sql = "SELECT distinct s.snum as ssnum, c.snum as ccnum FROM " + + DatabaseCreator.CUSTOMERS_TABLE + " c left outer join " + + DatabaseCreator.SALESPEOPLE_TABLE + " s on s.snum=c.snum"; + ResultSet result = statement.executeQuery(sql); + + HashMap<Integer, Integer> value = new HashMap<Integer, Integer>(); + value.put(1001, 1001); + value.put(1002, 1002); + value.put(1003, 1003); + value.put(1004, 1004); + value.put(1007, 1007); + + while (result.next()) { + int key = result.getInt("ssnum"); + Object val = result.getObject("ccnum"); + assertTrue("wrong value of ssnum field", value.containsKey(key)); + assertEquals("wrong value of ccnum field", value.get(key), + (Integer) val); + value.remove(key); + } + assertTrue("expected rows number doesn't equal actual rows number", + value.isEmpty()); + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectRightOuterJoin(). Selects + * records from a table using right join + * + * TODO RIGHT and FULL OUTER JOINs are not supported + */ +/* public void test_SelectRightOuterJoin() throws SQLException { + String sql = "SELECT distinct s.snum as ssnum, c.snum as ccnum FROM " + + DatabaseCreator.CUSTOMERS_TABLE + " c right outer join " + + DatabaseCreator.SALESPEOPLE_TABLE + " s on s.snum=c.snum"; + ResultSet result = statement.executeQuery(sql); + + HashMap<Integer, Integer> value = new HashMap<Integer, Integer>(); + value.put(1001, 1001); + value.put(1002, 1002); + value.put(1003, 1003); + value.put(1004, 1004); + value.put(1007, 1007); + value.put(1013, null); + + while (result.next()) { + int key = result.getInt("ssnum"); + Object val = result.getObject("ccnum"); + assertTrue("wrong value of ssnum field", value.containsKey(key)); + assertEquals("wrong value of ccnum field", value.get(key), + (Integer) val); + value.remove(key); + } + assertTrue("expected rows number doesn't equal actual rows number", + value.isEmpty()); + result.close(); + } +*/ + /** + * @tests SelectFunctionalityTest#test_SelectGroupBy(). Selects records from + * a table using group by + */ + public void test_SelectGroupBy() throws SQLException { + String selectQuery = "SELECT rating, SUM(snum) AS sum FROM " + + DatabaseCreator.CUSTOMERS_TABLE + " GROUP BY rating"; + ResultSet result = statement.executeQuery(selectQuery); + + HashMap<Integer, Integer> values = new HashMap<Integer, Integer>(); + values.put(100, 3006); + values.put(200, 2005); + values.put(300, 2009); + + while (result.next()) { + int rating = result.getInt("rating"); + int sum = result.getInt("sum"); + assertTrue("Wrong value of rating field", values + .containsKey(rating)); + assertEquals("Wrong value of sum field", values.get(rating), + new Integer(sum)); + assertEquals(new Integer(sum), values.remove(rating)); + } + result.close(); + assertTrue("Result set has wrong size", values.isEmpty()); + } + + /** + * @tests SelectFunctionalityTest#test_SelectOrderBy(). Selects records from + * a table using order by + */ + public void test_SelectOrderBy() throws SQLException { + String selectQuery = "SELECT onum FROM " + DatabaseCreator.ORDERS_TABLE + + " ORDER BY onum"; + ResultSet result = statement.executeQuery(selectQuery); + + ArrayList<Integer> values = new ArrayList<Integer>(); + values.add(Integer.valueOf(3001)); + values.add(Integer.valueOf(3002)); + values.add(Integer.valueOf(3003)); + values.add(Integer.valueOf(3005)); + values.add(Integer.valueOf(3006)); + values.add(Integer.valueOf(3007)); + values.add(Integer.valueOf(3008)); + values.add(Integer.valueOf(3009)); + values.add(Integer.valueOf(3010)); + values.add(Integer.valueOf(3011)); + + int index = 0; + while (result.next()) { + Integer onum = result.getInt("onum"); + assertTrue("result set doesn't contain value", values + .contains(onum)); + assertEquals("result set is not sorted", index, values + .indexOf(onum)); + index++; + } + result.close(); + } + + /** + * @tests SelectFunctionalityTest#test_SelectDistinct(). Selects records + * from a table using distinct + */ + public void test_SelectDistinct() throws SQLException { + String selectQuery = "SELECT DISTINCT rating FROM " + + DatabaseCreator.CUSTOMERS_TABLE; + ResultSet result = statement.executeQuery(selectQuery); + + HashSet<Integer> values = new HashSet<Integer>(); + values.add(Integer.valueOf(100)); + values.add(Integer.valueOf(200)); + values.add(Integer.valueOf(300)); + + while (result.next()) { + Integer rating = result.getInt("rating"); + assertTrue("result set doesn't contain value", values + .contains(rating)); + assertTrue("wrong value in the result set", values.remove(rating)); + } + result.close(); + assertTrue("Result set has wrong size", values.isEmpty()); + } + + /** + * @tests SelectFunctionalityTest#test_SelectAgregateFunctions(). Selects + * records from a table using agregate functions + */ + public void test_SelectAgregateFunctions() throws SQLException { + String selectCount = "SELECT count(onum) as count FROM " + + DatabaseCreator.ORDERS_TABLE; + String selectSum = "SELECT sum(onum) as sum FROM " + + DatabaseCreator.ORDERS_TABLE; + String selectAvg = "SELECT avg(onum) as avg FROM " + + DatabaseCreator.ORDERS_TABLE; + String selectMax = "SELECT max(onum) as max FROM " + + DatabaseCreator.ORDERS_TABLE; + String selectMin = "SELECT min(onum) as min FROM " + + DatabaseCreator.ORDERS_TABLE; + + func("count", selectCount, 10); + func("sum", selectSum, 30062); + func("avg", selectAvg, 3006); + func("max", selectMax, 3011); + func("min", selectMin, 3001); + } + + private void func(String name, String query, int expected) { + try { + ResultSet result = statement.executeQuery(query); + while (result.next()) { + assertEquals("wrong value of " + name + " field", expected, + result.getInt(name)); + } + assertFalse("wrong size of result set", result.next()); + result.close(); + } catch (SQLException e) { + fail(e.getMessage()); + } + } + + /** + * @tests SelectFunctionalityTest#test_SelectHaving(). Selects records from + * a table using having + */ + public void test_SelectHaving() throws SQLException { + String selectQuery = "SELECT snum, max(amt) AS max FROM " + + DatabaseCreator.ORDERS_TABLE + + " GROUP BY snum HAVING max(amt) > 3000"; + ResultSet result = statement.executeQuery(selectQuery); + + HashSet<Double> values = new HashSet<Double>(); + values.add(Double.valueOf(9891.88)); + values.add(Double.valueOf(5160.45)); + + while (result.next()) { + Double max = result.getDouble("max"); + assertTrue("result set doesn't contain value", values.contains(max)); + assertTrue("wrong value in the result set", values.remove(max)); + } + result.close(); + assertTrue("Result set has wrong size", values.isEmpty()); + } +} diff --git a/sql/src/test/java/tests/java/sql/StressTest.java b/sql/src/test/java/tests/java/sql/StressTest.java new file mode 100755 index 0000000..fbafe82 --- /dev/null +++ b/sql/src/test/java/tests/java/sql/StressTest.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Vector; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; +import tests.support.ThreadPool; +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class StressTest extends TestCase { + Vector<Connection> vc = new Vector<Connection>(); + + private static Connection conn; + + private static Statement statement; + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite(StressTest.class)) { + + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } + + protected void tearDown() throws Exception { + dropTestTables(); + statement.close(); + conn.close(); + } + + private void createTestTables() { + try { + DatabaseMetaData meta = conn.getMetaData(); + ResultSet userTab = meta.getTables(null, null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.TEST_TABLE2)) { + statement.execute(DatabaseCreator.DROP_TABLE2); + } + } + statement.execute(DatabaseCreator.CREATE_TABLE2); + } catch (SQLException sql) { + fail("Unexpected SQLException " + sql.toString()); + } + return; + } + + private void dropTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE2); + } catch (SQLException sql) { + fail("Unexpected SQLException " + sql.toString()); + } + return; + } + }; + return setup; + } + + /** + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + vc.clear(); + } + + /** + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + closeConnections(); + statement.execute("DELETE FROM " + DatabaseCreator.TEST_TABLE2); + super.tearDown(); + } + + /** + * @tests StressTest#testManyConnectionsUsingOneThread(). Create many + * connections to the DataBase using one thread. + */ + public void testManyConnectionsUsingOneThread() { + try { + int maxConnections = getConnectionNum(); + openConnections(maxConnections); + assertEquals("Incorrect number of created connections", + maxConnections, vc.size()); + } catch (Exception e) { + fail("Unexpected Exception " + e.toString()); + } + } + + /** + * @tests StressTest#testManyConnectionsUsingManyThreads(). Create many + * connections to the DataBase using some threads. + */ + public void testManyConnectionsUsingManyThreads() { + int numTasks = getConnectionNum(); + + ThreadPool threadPool = new ThreadPool(numTasks); + + // run example tasks + for (int i = 0; i < numTasks; i++) { + threadPool.runTask(createTask(i)); + } + // close the pool and wait for all tasks to finish. + threadPool.join(); + assertEquals("Unable to create a connection", numTasks, vc.size()); + if (numTasks != Support_SQL.sqlMaxConnections) { + try { + // try to create connection n + 1 + Connection c = Support_SQL.getConnection(); + c.close(); + fail("It is possible to create more than " + numTasks + + "connections"); + } catch (SQLException sql) { + // expected + } + } + } + + /** + * @tests StressTest#testInsertOfManyRowsUsingOneThread(). Insert a lot of + * records to the DataBase using a maximum number of connections. + */ + public void testInsertOfManyRowsUsingOneThread() { + // TODO Crashes VM. Fix later. + /* + * int maxConnections = getConnectionNum(); + * openConnections(maxConnections); int tasksPerConnection = + * Support_SQL.sqlMaxTasks / maxConnections; int pk = 1; for (int i = 0; + * i < vc.size(); ++i) { Connection c = vc.elementAt(i); for (int j = 0; + * j < tasksPerConnection; ++j) { insertNewRecord(c, pk++); } } try { + * ResultSet rs = statement.executeQuery("SELECT COUNT(*) as counter + * FROM " + DatabaseCreator.TEST_TABLE2); assertTrue("RecordSet is + * empty", rs.next()); assertEquals("Incorrect number of records", + * tasksPerConnection * maxConnections, rs.getInt("counter")); + * rs.close(); } catch (SQLException sql) { fail("Unexpected + * SQLException " + sql.toString()); } + */ + } + + /** + * @tests + */ + public void testInsertOfManyRowsUsingManyThreads() { + // TODO Crashes VM. Fix later. + /* + * int numConnections = getConnectionNum(); + * + * ThreadPool threadPool = new ThreadPool(numConnections); + * + * for (int i = 0; i < numConnections; ++i) { + * threadPool.runTask(insertTask(numConnections, i)); } + * // close the pool and wait for all tasks to finish. + * threadPool.join(); assertEquals("Unable to create a connection", + * numConnections, vc.size()); try { ResultSet rs = + * statement.executeQuery("SELECT COUNT(*) as counter FROM " + + * DatabaseCreator.TEST_TABLE2); assertTrue("RecordSet is empty", + * rs.next()); int tasksPerConnection = Support_SQL.sqlMaxTasks / + * numConnections; assertEquals("Incorrect number of records", + * tasksPerConnection * numConnections, rs.getInt("counter")); + * rs.close(); } catch (SQLException sql) { fail("Unexpected + * SQLException " + sql.toString()); } + */ + } + + private int getConnectionNum() { + int num = Support_SQL.sqlMaxConnections; + try { + int mc = conn.getMetaData().getMaxConnections(); + if (mc != 0) { + if (num != mc) { + System.err.println("Will be used no more than " + mc + + " connections to the DataBase"); + } + num = mc; + } + } catch (SQLException sql) { + fail("Unexpected SQLException " + sql.toString()); + } + return num; + } + + private void openConnections(int maxConnections) { + int i = 0; + try { + for (; i < maxConnections; ++i) { + Connection c = Support_SQL.getConnection(); + if (c == null) { + assertEquals("Unable to create a connection", + maxConnections, i); + } + vc.add(c); + } + } catch (SQLException sql) { + assertEquals("Unable to create a connection", maxConnections, i); + } + return; + } + + private void closeConnections() { + int i = 0; + try { + for (; i < vc.size(); ++i) { + vc.elementAt(i).close(); + } + } catch (SQLException sql) { + assertEquals("Unable to close a connection", vc.size(), i); + } + return; + } + + private Runnable createTask(final int taskID) { + return new Runnable() { + public void run() { + try { + Connection c = Support_SQL.getConnection(); + if (c == null) { + return; + } + synchronized (this) { + vc.add(c); + } + } catch (SQLException sql) { + // nothing to do + } + } + }; + } + + private Runnable insertTask(final int numConnections, final int taskID) { + return new Runnable() { + public void run() { + try { + Connection c = Support_SQL.getConnection(); + if (c == null) { + return; + } + synchronized (this) { + vc.add(c); + } + int tasksPerConnection = Support_SQL.sqlMaxTasks + / numConnections; + for (int i = 0; i < tasksPerConnection; ++i) { + insertNewRecord(c, (i + 1) + tasksPerConnection + * taskID); + } + } catch (SQLException sql) { + // do nothing + } + } + }; + } + + private void insertNewRecord(Connection c, int pk) { + String query = "INSERT INTO " + DatabaseCreator.TEST_TABLE2 + + "(finteger, ftext, fcharacter, fdecimal, fnumeric," + + " fsmallint, ffloat, freal, fdouble, fdate, ftime)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + try { + PreparedStatement ps = c.prepareStatement(query); + ps.setInt(1, pk); + ps.setString(2, "text"); + ps.setString(3, "chr"); + ps.setFloat(4, 0.1f); + ps.setFloat(5, 0.2f); + ps.setShort(6, (short) 3); + ps.setFloat(7, 0.4f); + ps.setDouble(8, 0.5); + ps.setDouble(9, 0.6); + ps.setDate(10, new java.sql.Date(System.currentTimeMillis())); + ps.setTime(11, new java.sql.Time(System.currentTimeMillis())); + ps.execute(); + ps.close(); + } catch (SQLException sql) { + fail("Unexpected SQLException " + sql.toString()); + } + return; + } +} diff --git a/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest.java b/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest.java new file mode 100755 index 0000000..b9761cd --- /dev/null +++ b/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest.java @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashSet; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class UpdateFunctionalityTest extends TestCase { + + private static final int numberOfRecords = 20; + + private static Connection conn; + + private static Statement statement; + + protected void setUp() throws Exception { + super.setUp(); + DatabaseCreator.fillTestTable1(conn, numberOfRecords); + DatabaseCreator.fillTestTable2(conn, numberOfRecords); + } + + protected void tearDown() throws Exception { + String deleteQuery1 = "DELETE FROM " + DatabaseCreator.TEST_TABLE1; + String deleteQuery2 = "DELETE FROM " + DatabaseCreator.TEST_TABLE2; + + statement.execute(deleteQuery1); + statement.execute(deleteQuery2); + super.tearDown(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + UpdateFunctionalityTest.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + statement.close(); + conn.close(); + } + + private void createTestTables() { + try { + DatabaseMetaData meta = conn.getMetaData(); + ResultSet userTab = meta.getTables(null, null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { + statement.execute(DatabaseCreator.DROP_TABLE1); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE2)) { + statement.execute(DatabaseCreator.DROP_TABLE2); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE3)) { + statement.execute(DatabaseCreator.DROP_TABLE3); + } + } + userTab.close(); + + statement.execute(DatabaseCreator.CREATE_TABLE3); + statement.execute(DatabaseCreator.CREATE_TABLE2); + statement.execute(DatabaseCreator.CREATE_TABLE1); + + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE1); + statement.execute(DatabaseCreator.DROP_TABLE2); + statement.execute(DatabaseCreator.DROP_TABLE3); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests UpdateFunctionalityTest#testUpdate1(). Updates all values in one + * column in the table + */ + public void testUpdate1() { + String newValue = "newValue"; + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field1='" + newValue + "'"; + try { + int num = statement.executeUpdate(updateQuery); + assertEquals("Not all records in the database were updated", + numberOfRecords, num); + String selectQuery = "SELECT field1 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + assertEquals("The field field1 was not updated", newValue, + result.getString("field1")); + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate2(). Updates values in one + * column in the table using where condition in update command + */ + public void testUpdate2() { + String newValue = "newValue"; + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field1='" + newValue + "' WHERE (id > 2) and (id < 10)"; + try { + int num = statement.executeUpdate(updateQuery); + int expectedUpdated = 7; + assertEquals("Not all records in the database were updated", + expectedUpdated, num); + String selectQuery = "SELECT * FROM " + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + int id = result.getInt("id"); + String field1 = result.getString("field1"); + if ((id > 2) && (id < 10)) { + assertEquals("The field field1 was not updated", newValue, + field1); + } else { + assertEquals("The field field1 was not updated", + DatabaseCreator.defaultString + id, field1); + } + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate3(). Updates values in a several + * columns in the table + */ + public void testUpdate3() { + int newValue1 = -1; + int newValue2 = -2; + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2=" + newValue1 + ", field3=" + newValue2; + try { + int num = statement.executeUpdate(updateQuery); + assertEquals("Not all records in the database were updated", + numberOfRecords, num); + String selectQuery = "SELECT field2, field3 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + // TODO getBigDecimal is not supported +// assertEquals("The field field2 was not updated", newValue1, +// result.getBigDecimal("field2").intValue()); +// assertEquals("The field field3 was not updated", newValue2, +// result.getBigDecimal("field3").intValue()); + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate4(). Updates values in a several + * columns in the table using where condition in update command + */ + public void testUpdate4() { + int newValue1 = -1; + int newValue2 = -2; + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2=" + newValue1 + ", field3=" + newValue2 + + " WHERE id > 10"; + try { + int num = statement.executeUpdate(updateQuery); + int expectedUpdated = 9; + assertEquals("Not all records in the database were updated", + expectedUpdated, num); + String selectQuery = "SELECT id, field2, field3 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + int id = result.getInt("id"); + // TODO getBigDecimal is not supported +// int value2 = result.getBigDecimal("field2").intValue(); +// int value3 = result.getBigDecimal("field3").intValue(); +// if (id > expectedUpdated + 1) { +// assertEquals("The field field2 was not updated", newValue1, +// value2); +// assertEquals("The field field3 was not updated", newValue2, +// value3); +// } else { +// assertEquals("The field field2 was not updated", id, value2); +// assertEquals("The field field3 was not updated", id, value3); +// } + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate5(). Updates values in one + * columns in the table using condition + */ + public void testUpdate5() { + int factor = 3; + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2=field2 *" + factor; + try { + String selectQuery = "SELECT field2 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + HashSet<BigDecimal> values = new HashSet<BigDecimal>(); + // TODO getBigDecimal is not supported +// while (result.next()) { +// values.add(BigDecimal.valueOf(result.getBigDecimal("field2") +// .intValue() +// * factor)); +// } + + int num = statement.executeUpdate(updateQuery); + assertEquals("Not all records in the database were updated", + numberOfRecords, num); + result = statement.executeQuery(selectQuery); + // TODO getBigDecimal is not supported +// while (result.next()) { +// BigDecimal value = result.getBigDecimal("field2"); +// assertTrue("Wrong value of field2 after update" +// + value.intValue(), values.remove(value)); +// } + assertTrue("Not all records were updated", values.isEmpty()); + + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate6(). Sets value of field2 to + * default + */ + public void testUpdate6() { + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2='1'"; + try { + + int num = statement.executeUpdate(updateQuery); + assertEquals("Not all records in the database were updated", + numberOfRecords, num); + String selectQuery = "SELECT field2 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + // TODO getBigDecimal is not supported +// while (result.next()) { +// assertEquals("value of field2 should be default ", +// DatabaseCreator.defaultInt, result.getBigDecimal( +// "field2").intValue()); +// } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate7(). Updates records in the + * table using subquery in update command + */ + public void testUpdate7() { + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2='1' WHERE id < ( SELECT COUNT(*) FROM " + + DatabaseCreator.TEST_TABLE2 + " WHERE finteger > 15)"; + try { + int num = statement.executeUpdate(updateQuery); + int expectedUpdated = 4; + assertEquals("Not all records in the database were updated", + expectedUpdated, num); + String selectQuery = "SELECT id, field2 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + // TODO getBigDecimal is not supported +// int value = result.getBigDecimal("field2").intValue(); +// int id = result.getInt("id"); +// if (id < expectedUpdated) { +// assertEquals("value of field2 should be default ", +// DatabaseCreator.defaultInt, value); +// } else { +// assertEquals("wrong value of field2", id, value); +// } + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } + + /** + * @tests UpdateFunctionalityTest#testUpdate8(). Sets value of field2 to + * NULL + */ + public void testUpdate8() { + String updateQuery = "UPDATE " + DatabaseCreator.TEST_TABLE1 + + " SET field2=NULL"; + try { + + int num = statement.executeUpdate(updateQuery); + assertEquals("Not all records in the database were updated", + numberOfRecords, num); + String selectQuery = "SELECT field2 FROM " + + DatabaseCreator.TEST_TABLE1; + ResultSet result = statement.executeQuery(selectQuery); + while (result.next()) { + assertNull("value of field2 should be NULL", result + .getObject("field2")); + } + result.close(); + } catch (SQLException e) { + fail("Unexpected exception" + e.getMessage()); + } + } +} diff --git a/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest2.java b/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest2.java new file mode 100755 index 0000000..7bcbff6 --- /dev/null +++ b/sql/src/test/java/tests/java/sql/UpdateFunctionalityTest2.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.java.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import tests.support.DatabaseCreator; +import tests.support.Support_SQL; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class UpdateFunctionalityTest2 extends TestCase { + + private static Connection conn = null; + + private static Statement statement = null; + + protected void setUp() throws Exception { + super.setUp(); + DatabaseCreator.fillParentTable(conn); + DatabaseCreator.fillSimpleTable3(conn); + DatabaseCreator.fillSimpleTable1(conn); + } + + protected void tearDown() throws Exception { + statement.execute("DELETE FROM " + DatabaseCreator.SIMPLE_TABLE3); + statement.execute("DELETE FROM " + DatabaseCreator.SIMPLE_TABLE1); + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.FKCASCADE_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.PARENT_TABLE); + statement.execute("DELETE FROM " + DatabaseCreator.TEST_TABLE5); + super.tearDown(); + } + + public static Test suite() { + TestSetup setup = new TestSetup(new TestSuite( + UpdateFunctionalityTest2.class)) { + protected void setUp() throws Exception { + Support_SQL.loadDriver(); + try { + conn = Support_SQL.getConnection(); + statement = conn.createStatement(); + createTestTables(); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + protected void tearDown() throws Exception { + deleteTestTables(); + statement.close(); + conn.close(); + } + + private void createTestTables() { + try { + DatabaseMetaData meta = conn.getMetaData(); + ResultSet userTab = meta.getTables(null, null, null, null); + + while (userTab.next()) { + String tableName = userTab.getString("TABLE_NAME"); + if (tableName.equals(DatabaseCreator.PARENT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_PARENT); + } else if (tableName + .equals(DatabaseCreator.FKCASCADE_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + } else if (tableName + .equals(DatabaseCreator.FKSTRICT_TABLE)) { + statement + .execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + } else if (tableName + .equals(DatabaseCreator.SIMPLE_TABLE1)) { + statement + .execute(DatabaseCreator.DROP_TABLE_SIMPLE1); + } else if (tableName + .equals(DatabaseCreator.SIMPLE_TABLE3)) { + statement + .execute(DatabaseCreator.DROP_TABLE_SIMPLE3); + } else if (tableName + .equals(DatabaseCreator.TEST_TABLE5)) { + statement.execute(DatabaseCreator.DROP_TABLE5); + } + } + userTab.close(); + statement.execute(DatabaseCreator.CREATE_TABLE_PARENT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.CREATE_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.CREATE_TABLE_SIMPLE3); + statement.execute(DatabaseCreator.CREATE_TABLE_SIMPLE1); + statement.execute(DatabaseCreator.CREATE_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + + private void deleteTestTables() { + try { + statement.execute(DatabaseCreator.DROP_TABLE_FKCASCADE); + statement.execute(DatabaseCreator.DROP_TABLE_FKSTRICT); + statement.execute(DatabaseCreator.DROP_TABLE_PARENT); + statement.execute(DatabaseCreator.DROP_TABLE_SIMPLE3); + statement.execute(DatabaseCreator.DROP_TABLE_SIMPLE1); + statement.execute(DatabaseCreator.DROP_TABLE5); + } catch (SQLException e) { + fail("Unexpected SQLException " + e.toString()); + } + } + }; + return setup; + } + + /** + * @tests UpdateFunctionalityTest2#testUpdate1(). Updates row with no + * referencing ones and RESTRICT action + */ + public void testUpdate1() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("UPDATE " + DatabaseCreator.PARENT_TABLE + + " SET id = 4 WHERE id = 3"); + } + + /** + * @tests UpdateFunctionalityTest2#testUpdate2(). Attempts to update row + * with referencing ones and RESTRICT action - expecting SQLException + * + * TODO not supported + */ +/* public void testUpdate2() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + try { + statement.execute("UPDATE " + DatabaseCreator.PARENT_TABLE + + " SET id = 5 WHERE id = 1;"); + fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + + } + } +*/ + /** + * @tests UpdateFunctionalityTest2#testUpdate3(). Deletes all referencing + * rows and then updates referenced one + */ + public void testUpdate3() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("DELETE FROM " + DatabaseCreator.FKSTRICT_TABLE + + " WHERE name_id = 1;"); + statement.execute("UPDATE " + DatabaseCreator.PARENT_TABLE + + " SET id = 5 WHERE id = 1;"); + } + + /** + * @tests UpdateFunctionalityTest2#testUpdate4(). Attempts to set incorrect + * foreign key value - expecting SQLException + * + * TODO foreign key functionality is not supported + */ +/* public void testUpdate4() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + try { + statement.execute("UPDATE " + DatabaseCreator.FKSTRICT_TABLE + + " SET name_id = 6 WHERE name_id = 2"); + fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + } + } +*/ + /** + * @tests UpdateFunctionalityTest2#testUpdate5(). Updates row with + * referencing ones and CASCADE action - expecting that all + * referencing rows will also be updated + */ + public void testUpdate5() throws SQLException { + DatabaseCreator.fillFKCascadeTable(conn); + statement.execute("UPDATE " + DatabaseCreator.PARENT_TABLE + + " SET id = 5 WHERE id = 1;"); + + ResultSet r = statement.executeQuery("SELECT COUNT(*) " + "FROM " + + DatabaseCreator.FKCASCADE_TABLE + " WHERE name_id = 1;"); + r.next(); + assertEquals("Should be 2 rows", 2, r.getInt(1)); + r = statement.executeQuery("SELECT COUNT(*) " + "FROM " + + DatabaseCreator.FKCASCADE_TABLE + " WHERE name_id = 5;"); + r.next(); + assertEquals("Should be 0 rows", 0, r.getInt(1)); + r.close(); + } + + /** + * @tests UpdateFunctionalityTest2#testUpdate6(). Attempts to set incorrect + * foreign key value to row with CASCADE action - expecting + * SQLException + * + * TODO Foreign key functionality is not supported + */ + /* public void testUpdate6() throws SQLException { + DatabaseCreator.fillFKCascadeTable(conn); + try { + statement.execute("UPDATE " + DatabaseCreator.FKCASCADE_TABLE + + " SET name_id = 6 WHERE name_id = 2"); + fail("expecting SQLException"); + } catch (SQLException ex) { + // expected + } + } +*/ + /** + * @tests UpdateFunctionalityTest2#testUpdate7(). Updates table using + * subquery in WHERE clause + * + * TODO Foreign key functionality is not supported + */ +/* public void testUpdate7() throws SQLException { + DatabaseCreator.fillFKStrictTable(conn); + statement.execute("UPDATE " + DatabaseCreator.FKSTRICT_TABLE + + " SET value = 'updated' WHERE name_id = ANY (SELECT id FROM " + + DatabaseCreator.PARENT_TABLE + " WHERE id > 1)"); + ResultSet r = statement.executeQuery("SELECT COUNT(*) FROM " + + DatabaseCreator.FKSTRICT_TABLE + " WHERE value = 'updated';"); + r.next(); + assertEquals("Should be 1 row", 1, r.getInt(1)); + r.close(); + } +*/ + /** + * @tests UpdateFunctionalityTest2#testUpdate8(). Updates table using scalar + * subquery as new field value + */ + public void testUpdate8() throws SQLException { + statement.execute("UPDATE " + DatabaseCreator.SIMPLE_TABLE3 + + " SET speed = (SELECT MAX(speed) FROM " + + DatabaseCreator.SIMPLE_TABLE1 + + ") WHERE id = (SELECT id FROM " + + DatabaseCreator.SIMPLE_TABLE1 + + " WHERE speed = (SELECT MAX(speed) FROM " + + DatabaseCreator.SIMPLE_TABLE1 + "))"); + ResultSet r = statement.executeQuery("SELECT id FROM " + + DatabaseCreator.SIMPLE_TABLE3 + + " WHERE speed = (SELECT MAX(speed) FROM " + + DatabaseCreator.SIMPLE_TABLE1 + ");"); + r.next(); + assertEquals("Incorrect id updated", 1, r.getInt(1)); + r.close(); + } + + /** + * @tests UpdateFunctionalityTest2#testUpdate9(). Updates table using + * PreparedStatement + */ + public void testUpdate9() throws SQLException { + DatabaseCreator.fillTestTable5(conn); + PreparedStatement stat = conn.prepareStatement("UPDATE " + + DatabaseCreator.TEST_TABLE5 + + " SET testValue = ? WHERE testID = ?"); + stat.setString(1, "1"); + stat.setInt(2, 1); + stat.execute(); + stat.setString(1, "2"); + stat.setInt(2, 2); + stat.execute(); + ResultSet r = statement.executeQuery("SELECT testId, testValue FROM " + + DatabaseCreator.TEST_TABLE5 + + " WHERE testID < 3 ORDER BY testID"); + while (r.next()) { + assertEquals("Incorrect value was returned", new Integer(r + .getInt(1)).toString(), r.getString(2)); + } + r.close(); + stat.close(); + } +} diff --git a/sql/src/test/java/tests/sql/AbstractSqlTest.java b/sql/src/test/java/tests/sql/AbstractSqlTest.java new file mode 100644 index 0000000..9d922db --- /dev/null +++ b/sql/src/test/java/tests/sql/AbstractSqlTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import junit.framework.TestCase; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + + +/** + * This class provides SQL unit test, which can be used by subclasses eg. to + * test JDBC drivers. + */ +public abstract class AbstractSqlTest extends TestCase { + + /** + * The first connection. + */ + private Connection firstConnection; + + /** + * The second connection. + */ + private Connection secondConnection; + + /** + * The statement from the first connection. + */ + private Statement firstStmt; + + /** + * The statement from the second connection. + */ + private Statement secondStmt; + + /** + * The values of the first column "one". + */ + private final String[] ones = {"hello!", "goodbye"}; + + /** + * The values of the second column "two". + */ + private final short[] twos = {10, 20}; + + /** + * The updated values of the first column "one". + */ + private final String[] ones_updated; + + /** Creates a new instance of this class */ + public AbstractSqlTest(String testName) { + super(testName); + ones_updated = new String[ones.length]; + for (int i = 0; i < ones.length; i++) { + ones_updated[i] = ones[i] + twos[i]; + } + } + + /** + * Sets up a unit test, by creating two statements from two connections and + * creating a test table. + * + * @exception SQLException if there is a problem accessing the database + * @exception Exception may be thrown by subclasses + */ + @Override + protected void setUp() throws SQLException, Exception { + Class.forName(getDriverClassName()).newInstance(); + firstConnection = DriverManager.getConnection(getConnectionURL()); + firstConnection.setTransactionIsolation(getTransactionIsolation()); + secondConnection = DriverManager.getConnection(getConnectionURL()); + secondConnection.setTransactionIsolation(getTransactionIsolation()); + firstStmt = firstConnection.createStatement(); + firstStmt.execute("create table tbl1(one varchar(10), two smallint)"); + secondStmt = secondConnection.createStatement(); + } + + /** + * Tears down a unit test, by setting the auto commit property of the first + * connection back to true, dropping the test table and closing the two + * connections. + */ + @Override + protected void tearDown() throws SQLException { + firstStmt.close(); + secondStmt.close(); + firstConnection.setAutoCommit(true); + firstStmt = firstConnection.createStatement(); + firstStmt.execute("drop table tbl1"); + firstStmt.close(); + firstConnection.close(); + secondConnection.close(); + } + + /** + * Adds some rows to the test table and asserts that the rows can be + * retrieved again. + * + * @throws SQLException if there is a problem accessing the database + */ + private void autoCommitInsertSelect() throws SQLException { + firstStmt.getConnection().setAutoCommit(true); + for (int i = 0; i < ones.length; i++) { + firstStmt.execute("insert into tbl1 values('" + ones[i] + "'," + + twos[i] + ")"); + } + assertAllFromTbl1(firstStmt, ones, twos); + } + + /** + * Asserts that the expected values can be selected from the test table. + * + * @param stmt the statement to be used for the selection of the data + * @param ones the expected values of the column 'one' + * @param twos the expected values of the column 'two' + * @throws SQLException if there is a problem accessing the database + */ + private void assertAllFromTbl1(Statement stmt, String[] ones, short[] twos) + throws SQLException { + ResultSet rs = stmt.executeQuery("select * from tbl1"); + int i = 0; + for (; rs.next(); i++) { + assertTrue(i < ones.length); + assertEquals(ones[i], rs.getString("one")); + assertEquals(twos[i], rs.getShort("two")); + } + assertTrue(i == ones.length); + } + + public void testAutoCommitInsertSelect() throws SQLException{ + autoCommitInsertSelect(); + } + + /** + * Tests the following sequence after successful insertion of some test + * data: + * - update data from connection one + * - select data from connection two (-> should have the old values) + * - commit data from connection one + * - select data from connection two (-> should have the new values) + * + * @throws SQLException if there is a problem accessing the database + */ + public void testUpdateSelectCommitSelect() throws SQLException { + autoCommitInsertSelect(); + firstStmt.getConnection().setAutoCommit(false); + updateOnes(firstStmt, ones_updated, twos); + assertAllFromTbl1(secondStmt, ones, twos); + firstStmt.getConnection().commit(); + assertAllFromTbl1(secondStmt, ones_updated, twos); + } + + /** + * Tests the following sequence after successful insertion of some test + * data: + * - update data from connection one + * - select data from connection two (-> should have the old values) + * - rollback data from connection one + * - select data from connection two (-> should still have the old values) + * + * @throws SQLException if there is a problem accessing the database + */ + public void testUpdateSelectRollbackSelect() throws SQLException { + autoCommitInsertSelect(); + firstStmt.getConnection().setAutoCommit(false); + updateOnes(firstStmt, ones_updated, twos); + assertAllFromTbl1(secondStmt, ones, twos); + firstStmt.getConnection().rollback(); + assertAllFromTbl1(secondStmt, ones, twos); + } + + /** + * Updates the values in column 'one' + * @param stmt the statement to be used to update the data + * @param ones_updated the updated valus of column 'one' + * @param twos the reference values of column 'two' + * @throws SQLException if there is a problem accessing the database + */ + private void updateOnes(Statement stmt, String[] ones_updated, short[] twos) + throws SQLException { + for (int i = 0; i < ones_updated.length; i++) { + stmt.execute("UPDATE tbl1 SET one = '" + ones_updated[i] + + "' WHERE two = " + twos[i]); + } + } + + protected abstract String getConnectionURL(); + + protected abstract String getDriverClassName(); + + protected abstract int getTransactionIsolation(); + +} diff --git a/sql/src/test/java/tests/sql/AllTests.java b/sql/src/test/java/tests/sql/AllTests.java new file mode 100644 index 0000000..afd9ba3 --- /dev/null +++ b/sql/src/test/java/tests/sql/AllTests.java @@ -0,0 +1,46 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Test suite that includes all tests for the Math project. + */ +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = new TestSuite("All SQL test suites"); + // $JUnit-BEGIN$ + suite.addTest(org.apache.harmony.sql.tests.java.sql.AllTests.suite()); + suite.addTest(org.apache.harmony.sql.tests.javax.sql.AllTests.suite()); + suite.addTest(tests.java.sql.AllTests.suite()); + + suite.addTestSuite(SQLite.JDBCDriverTest.class); + suite.addTestSuite(tests.sql.ConnectionTest.class); + suite.addTestSuite(tests.sql.PreparedStatementTest.class); + suite.addTestSuite(tests.sql.ResultSetMetaDataTest.class); + suite.addTestSuite(tests.sql.StatementTest.class); + // $JUnit-END$ + return suite; + } +} diff --git a/sql/src/test/java/tests/sql/ConnectionTest.java b/sql/src/test/java/tests/sql/ConnectionTest.java new file mode 100755 index 0000000..ba6fff2 --- /dev/null +++ b/sql/src/test/java/tests/sql/ConnectionTest.java @@ -0,0 +1,1958 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLWarning; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import java.sql.CallableStatement; + +import junit.framework.Test; + +public class ConnectionTest extends SQLTest { + + /** + * @test java.sql.Connection#createStatement() + */ + public void testCreateStatement() { + + Statement statement = null; + try { + statement = conn.createStatement(); + statement.close(); + } catch (SQLException sqle) { + fail("SQL Exception was thrown: " + sqle.getMessage()); + } catch (Exception e) { + fail("Unexpected Exception " + e.getMessage()); + } + try { + statement.executeQuery("select * from zoo"); + fail("SQLException is not thrown after close"); + } catch (SQLException e) { + // expected + } + } + + /** + * @test java.sql.Connection#createStatement(int resultSetType, int + * resultSetConcurrency) + */ + public void testCreateStatement_int_int() { + Statement st = null; + ResultSet rs = null; + try { + st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + st.execute("select id, name from zoo"); + rs = st.getResultSet(); + try { + rs.deleteRow(); + fail("Can delete row for READ_ONLY ResultSet"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (Exception ee) { + } + } + + try { + st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("parrot", (rs.getString(1))); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (Exception ee) { + } + } + + try { + st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("bird", (rs.getString(1))); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (Exception ee) { + } + } + + try { + // exception is not specified for this case + conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, -1); + } catch (SQLException sqle) { + // expected + } + + try { + // exception is not specified for this case + conn.createStatement(Integer.MIN_VALUE, ResultSet.CONCUR_READ_ONLY); + } catch (SQLException sqle) { + // expected + } + } + + /** + * @test java.sql.Connection#createStatement(int resultSetType, int + * resultSetConcurrency, int resultSetHoldability) + */ + public void testCreateStatement_int_int_int() { + Statement st = null; + try { + st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.HOLD_CURSORS_OVER_COMMIT); + st.execute("select id, name from zoo"); + ResultSet rs = st.getResultSet(); + try { + rs.close(); + } catch (SQLException sqle) { + fail("Unexpected exception was thrown during closing ResultSet"); + } + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + /* + * ResultSet.CLOSE_CURSORS_AT_COMMIT is not supported + */ +/* try { + st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.CLOSE_CURSORS_AT_COMMIT); + st.execute("select id, name from zoo"); + ResultSet rs = st.getResultSet(); + try { + rs.close(); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } +*/ + try { + conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, -100); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } + + /** + * @test java.sql.Connection#getMetaData() + */ + public void testGetMetaData() { + try { + DatabaseMetaData md = conn.getMetaData(); + Connection con = md.getConnection(); + assertEquals(conn, con); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } + + /** + * @test java.sql.Connection#clearWarnings() + * + * TODO clearWarnings is not supported + */ +/* public void testClearWarnings() { + Statement st = null; + try { + st = conn.createStatement(); + st.execute("select animals from zoo"); + fail("SQLException was not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + conn.clearWarnings(); + SQLWarning w = conn.getWarnings(); + assertNull(w); + + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + + try { + st = conn.createStatement(); + st.execute("select monkey from zoo"); + fail("SQLException was not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + SQLWarning w = conn.getWarnings(); + assertNotNull(w); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + } +*/ + /** + * @test java.sql.Connection#getWarnings() + * + * TODO GetWarnings is not supported: returns null + */ + /* public void testGetWarnings() { + + Statement st = null; + int errorCode1 = -1; + int errorCode2 = -1; + + try { + st = conn.createStatement(); + st.execute("select animals from zoooo"); + fail("SQLException was not thrown"); + } catch (SQLException e) { + // expected + errorCode1 = e.getErrorCode(); + } + + try { + SQLWarning wrs = conn.getWarnings(); + assertEquals(errorCode1, wrs.getErrorCode()); + assertNull(wrs.getNextWarning()); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + try { + st.execute("select horse from zoooooo"); + } catch (SQLException e) { + // expected + errorCode2 = e.getErrorCode(); + } + + try { + SQLWarning wrs = conn.getWarnings(); + assertEquals(errorCode1, wrs.getErrorCode()); + assertNotNull(wrs.getNextWarning()); + assertEquals(errorCode2, wrs.getErrorCode()); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + + try { + st.close(); + } catch (SQLException ee) { + } + } +*/ + /** + * @test java.sql.Connection#getAutoCommit() + */ + public void testGetAutoCommit() { + try { + conn.setAutoCommit(true); + assertTrue(conn.getAutoCommit()); + conn.setAutoCommit(false); + assertFalse(conn.getAutoCommit()); + conn.setAutoCommit(true); + assertTrue(conn.getAutoCommit()); + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + } + + /** + * @test java.sql.Connection#setAutoCommit(boolean) + */ + public void testSetAutoCommit() { + Statement st = null; + ResultSet rs = null; + ResultSet rs1 = null; + try { + conn.setAutoCommit(true); + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Chichichi', 'monkey');"); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(3, getCount(rs)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + conn.setAutoCommit(false); + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (4, 'Burenka', 'cow');"); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(4, getCount(rs)); + conn.commit(); + rs1 = st.getResultSet(); + assertEquals(0, getCount(rs1)); + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + rs1.close(); + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Connection#isReadOnly() + */ + public void testIsReadOnly() { + try { + conn.setReadOnly(true); + assertTrue(conn.isReadOnly()); + conn.setReadOnly(false); + assertFalse(conn.isReadOnly()); + conn.setReadOnly(true); + assertTrue(conn.isReadOnly()); + conn.setReadOnly(false); + assertFalse(conn.isReadOnly()); + } catch (SQLException sqle) { + fail("SQLException was thrown: " + sqle.getMessage()); + } + } + + /** + * @test java.sql.Connection#setReadOnly(boolean) + */ + public void testSetReadOnly() { + Statement st = null; + try { + conn.setReadOnly(true); + st = conn.createStatement(); + st.execute("insert into zoo (id, name, family) values (3, 'ChiChiChi', 'monkey');"); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + conn.setReadOnly(false); + st = conn.createStatement(); + st.execute("insert into zoo (id, name, family) values (4, 'ChiChiChi', 'monkey');"); + } catch (SQLException sqle) { + fail("SQLException was thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Connection#getHoldability() + * + * TODO ResultSet.CLOSE_CURSORS_AT_COMMIT is not supported + */ + public void testGetHoldability() { + try { + // conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); + // assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, conn + // .getHoldability()); + conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, conn + .getHoldability()); + } catch (SQLException sqle) { + fail("SQLException was thrown: " + sqle.getMessage()); + } + } + + /** + * @test java.sql.Connection#setHoldability(int) + * + * TODO ResultSet.CLOSE_CURSORS_AT_COMMIT is not supported + */ + public void testSetHoldability() { + Statement st = null; + try { +// conn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); +// assertEquals(ResultSet.CLOSE_CURSORS_AT_COMMIT, conn +// .getHoldability()); + st = conn.createStatement(); + st.execute("select id, name from zoo"); + ResultSet rs = st.getResultSet(); + try { + rs.close(); + } catch (SQLException sqle) { + fail("Unexpected exception was thrown during closing ResultSet"); + } + conn.commit(); + conn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT); + assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, conn + .getHoldability()); + } catch (SQLException sqle) { + fail("SQLException was thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + conn.setHoldability(-1); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + + /** + * @test java.sql.Connection#getTransactionIsolation() + * + * TODO only Connection.TRANSACTION_SERIALIZABLE is supported + */ + public void testGetTransactionIsolation() { + try { +// conn +// .setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); +// assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn +// .getTransactionIsolation()); +// conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); +// assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn +// .getTransactionIsolation()); +// conn +// .setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); +// assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn +// .getTransactionIsolation()); + conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + assertEquals(Connection.TRANSACTION_SERIALIZABLE, conn + .getTransactionIsolation()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + } + + /** + * @test java.sql.Connection#setTransactionIsolation(int) + * + * TODO only Connection.TRANSACTION_SERIALIZABLE is supported + */ + public void testSetTransactionIsolation() { + try { +// conn +// .setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); +// assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn +// .getTransactionIsolation()); +// conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); +// assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn +// .getTransactionIsolation()); +// conn +// .setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); +// assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn +// .getTransactionIsolation()); + conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); + assertEquals(Connection.TRANSACTION_SERIALIZABLE, conn + .getTransactionIsolation()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + + try { + conn.setTransactionIsolation(-1); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + + /** + * @test java.sql.Connection#setCatalog(String catalog) + * + * TODO setCatalog method does nothing + */ +/* public void testSetCatalog() { + String[] catalogs = { "test", "test1", "test" }; + Statement st = null; + try { + for (int i = 0; i < catalogs.length; i++) { + conn.setCatalog(catalogs[i]); + assertEquals(catalogs[i], conn.getCatalog()); + st = conn.createStatement(); + st + .equals("create table test_table (id integer not null, name varchar(20), primary key(id));"); + st.equals("drop table test_table;"); + + } + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + conn.setCatalog(null); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + + try { + conn.setCatalog("not_exist"); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + } +*/ + /** + * @test java.sql.Connection#getCatalog() + * + * TODO getCatalog method returns "" + */ + /* public void testGetCatalog() { + try { + assertEquals("test", conn.getCatalog()); + } catch (SQLException sqle) { + fail("SQL Exception " + sqle.getMessage()); + } catch (Exception e) { + fail("Unexpected Exception " + e.getMessage()); + } + } +*/ + /** + * @test java.sql.Connection#setTypeMap(Map<String,Class<?>> map) + * + * TODO setTypeMap is not supported + */ +/* public void testSetTypeMap() { + try { + java.util.Map map = conn.getTypeMap(); + map + .put( + "org.apache.harmony.sql.tests.java.sql.TestHelper_Connection1", + Class.forName("TestHelper_Connection1")); + conn.setTypeMap(map); + assertEquals(map, conn.getTypeMap()); + } catch (SQLException sqle) { + fail("SQL Exception " + sqle.getMessage()); + } catch (Exception e) { + fail("Unexpected Exception " + e.getMessage()); + } + + try { + conn.setTypeMap(null); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + } +*/ + /** + * @test java.sql.Connection#getTypeMap() + * + * TODO getTypeMap is not supported + */ +/* public void testGetTypeMap() { + try { + java.util.Map map = conn.getTypeMap(); + map + .put( + "org.apache.harmony.sql.tests.java.sql.TestHelper_Connection1", + Class.forName("TestHelper_Connection1")); + conn.setTypeMap(map); + assertEquals(map, conn.getTypeMap()); + } catch (SQLException sqle) { + fail("SQL Exception " + sqle.getMessage()); + } catch (Exception e) { + fail("Unexpected Exception " + e.getMessage()); + } + } +*/ + /** + * @test java.sql.Connection#nativeSQL(String sql) + * + * TODO nativeSQL is not supported + */ +/* public void testNativeSQL() { + String[] queries = { + "select * from zoo;", + "insert into zoo (id, name, family) values (3, 'Chichichi', 'monkey');", + "create table zoo_office(id integer not null, name varchar(20), primary key(id));", + "drop table zoo_office;" }; + String[] native_queries = { + "select * from zoo;", + "insert into zoo (id, name, family) values (3, 'Chichichi', 'monkey');", + "create table zoo_office(id integer not null, name varchar(20), primary key(id));", + "drop table zoo_office;" }; + Statement st = null; + try { + for (int i = 0; i < queries.length; i++) { + String nativeQuery = conn.nativeSQL(queries[i]); + assertEquals(native_queries[i], nativeQuery); + st = conn.createStatement(); + st.execute(nativeQuery); + } + } catch (SQLException sqle) { + fail("SQL Exception " + sqle.getMessage()); + } catch (Exception e) { + fail("Unexpected Exception " + e.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + String[] inc_queries = { "", " ", "not query" }; + for (int i = 0; i < inc_queries.length; i++) { + try { + String nativeQuery = conn.nativeSQL(inc_queries[i]); + assertEquals(inc_queries[i], nativeQuery); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } + } +*/ + /** + * @test java.sql.Connection#prepareCall(String sql) + * + * TODO prepareCall is not supported + */ +/* public void testPrepareCall() { + createProcedure(); + CallableStatement cstmt = null; + ResultSet rs = null; + ResultSet rs1 = null; + Statement st = null; + Statement st1 = null; + try { + cstmt = conn.prepareCall("call welcomeAnimal(3, 'Petya', 'Cock')"); + st = conn.createStatement(); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + cstmt.execute(); + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(3, getCount(rs1)); + + } catch (SQLException e) { + fail("SQLException was thrown"); + } finally { + try { + st.close(); + st1.close(); + rs.close(); + rs1.close(); + cstmt.close(); + } catch (SQLException ee) { + } + } + + try { + conn.prepareCall("welcomeAnimal(4, 'Petya', 'Cock')"); + fail("SQL Exception is not thrown"); + } catch (SQLException e) { + // expected + } + + try { + conn.prepareCall(null); + fail("SQL Exception is not thrown"); + } catch (SQLException e) { + // expected + } + } +*/ + /** + * @test java.sql.Connection#prepareCall(String sql, int resultSetType, int + * resultSetConcurrency) + * + * TODO prepareCall is not supported + */ +/* public void testPrepareCall_String_int_int() { + CallableStatement cstmt = null; + ResultSet rs = null; + try { + String query = "call welcomeAnimal(3, 'Petya', 'Cock')"; + cstmt = conn.prepareCall(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + cstmt.execute("select id, name from zoo"); + rs = cstmt.getResultSet(); + try { + rs.deleteRow(); + fail("Can delete row for READ_ONLY ResultSet"); + } catch (SQLException sqle) { + // expected + } + + try { + rs.absolute(0); + fail("Can move cursor to the last position for TYPE_FORWARD_ONLY ResultSet"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + cstmt.close(); + } catch (Exception ee) { + } + } + Statement st = null; + try { + st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("parrot", (rs.getString(1))); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("bird", (rs.getString(1))); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (SQLException ee) { + } + } + + try { + conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, -1); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + conn.createStatement(Integer.MIN_VALUE, ResultSet.CONCUR_READ_ONLY); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + } +*/ + /** + * @test java.sql.Connection#prepareCall(String sql, int resultSetType, int + * resultSetConcurrency, int resultSetHoldability) + * + * TODO prepareCall is not supported + */ +/* public void testPrepareCall_String_int_int_int() { + CallableStatement cstmt = null; + ResultSet rs = null; + try { + String query = "call welcomeAnimal(?, ?, ?)"; + cstmt = conn.prepareCall(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.HOLD_CURSORS_OVER_COMMIT); + cstmt.setInt(1, 3); + cstmt.setString(2, "Petya"); + cstmt.setString(3, "Cock"); + cstmt.execute("select id, name from zoo"); + rs = cstmt.getResultSet(); + try { + rs.close(); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + fail("Unexpected exception was thrown during closing ResultSet"); + } + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + cstmt.close(); + } catch (Exception ee) { + } + } + + Statement st = null; + + try { + st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.CLOSE_CURSORS_AT_COMMIT); + st.execute("select id, name from zoo"); + rs = st.getResultSet(); + try { + rs.close(); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } + + try { + conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, -100); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } +*/ + /** + * @test java.sql.Connection#prepareStatement(String sql) + */ + /* + * TODO Crashes VM. Fix later. + * + * public void testPrepareStatement() { + * PreparedStatement prst = null; + * Statement st = null; + * ResultSet rs = null; + * ResultSet rs1 = null; * + * try { + * String update = "update zoo set family = ? where name = ?;"; + * prst = conn.prepareStatement(update); prst.setString(1, "cat"); + * prst.setString(2, "Yasha"); + * st = conn.createStatement(); + * st.execute("select * from zoo where family = 'cat'"); + * rs = st.getResultSet(); + * assertEquals(0, getCount(rs)); + * prst.executeUpdate(); + * st.execute("select * from zoo where family = 'cat'"); + * rs1 = st.getResultSet(); + * assertEquals(1, getCount(rs1)); + * } catch(SQLException e) { + * fail("SQLException is thrown: " + e.getMessage()); + * } finally { + * try { + * rs.close(); + * rs1.close(); + * prst.close(); + * st.close(); + * } catch(SQLException ee) { } + * } + * + * try { + * prst = conn.prepareStatement(""); + * prst.execute(); + * fail("SQLException is not thrown"); + * } catch (SQLException e) { + * //expected + * } + * + * try { + * conn.prepareStatement(null); + * fail("SQLException is not thrown"); + * } catch (SQLException e) { + * // expected + * } + * } + */ + + /** + * @test java.sql.Connection#prepareStatement(String sql, int + * autoGeneratedKeys) + */ +// TODO Crashes VM. Fix later. +/* public void testPrepareStatement_String_int() { + PreparedStatement prst = null; + PreparedStatement prst1 = null; + Statement st = null; + ResultSet rs = null; + ResultSet rs1 = null; + ResultSet rs4 = null; + ResultSet rs5 = null; + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + + // TODO Statement.RETURN_GENERATED_KEYS is not supported + prst = conn.prepareStatement(insert, + Statement.RETURN_GENERATED_KEYS); + prst.setInt(1, 8); + prst.setString(2, "Tuzik"); + prst.setString(3, "dog"); + st = conn.createStatement(); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + prst.execute(); + st.execute("select * from zoo where family = 'dog'"); + rs1 = st.getResultSet(); + assertEquals(1, getCount(rs1)); + + rs4 = prst.getGeneratedKeys(); + assertEquals(0, getCount(rs4)); + + + prst1 = conn.prepareStatement(insert, Statement.NO_GENERATED_KEYS); + prst1.setInt(1, 5); + prst1.setString(2, "Layka"); + prst1.setString(3, "dog"); + + prst1.execute(); + +// TODO getGeneratedKeys is not supported + + rs5 = prst1.getGeneratedKeys(); + assertEquals(0, getCount(rs5)); + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + rs1.close(); + rs4.close(); + rs5.close(); + prst.close(); + prst1.close(); + st.close(); + } catch (Exception ee) { + } + } + } +*/ + /** + * @test java.sql.Connection#commit() + */ + public void testCommit() { + Statement st = null; + Statement st1 = null; + Statement st2 = null; + Statement st3 = null; + ResultSet rs1 = null; + ResultSet rs2 = null; + ResultSet rs3 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + conn.commit(); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch(SQLException ee) {} + } + try { + conn.commit(); + st3 = conn.createStatement(); + st3.execute("select * from zoo"); + rs3 = st3.getResultSet(); + assertEquals(4, getCount(rs3)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs3.close(); + st3.close(); + } catch(SQLException ee) {} + } + + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + conn.commit(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException was thrown: " + sqle.toString()); + } finally { + try { + rs1.close(); + st.close(); + st1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.Connection#rollback() + */ + public void testRollback() { + Statement st = null; + Statement st1 = null; + ResultSet rs1 = null; + ResultSet rs2 = null; + ResultSet rs3 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + Statement st2 = null; + Statement st3 = null; + try { + conn.commit(); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + conn.rollback(); + st3 = conn.createStatement(); + st3.execute("select * from zoo"); + rs3 = st3.getResultSet(); + assertEquals(4, getCount(rs3)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + rs3.close(); + st2.close(); + st3.close(); + } catch (SQLException ee) { + } + } + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + conn.rollback(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } finally { + try { + st.close(); + st1.close(); + rs1.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Connection#setSavepoint() + * + * TODO setSavepoint is not supported + */ +/* public void testSetSavepoint() { + Statement st = null; + Statement st1 = null; + ResultSet rs1 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + Statement st2 = null; + ResultSet rs2 = null; + try { + Savepoint sp = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (Exception ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(sp1); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + Savepoint sp = conn.setSavepoint(); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } finally { + try { + rs1.close(); + st.close(); + st1.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Connection#setSavepoint(String name) + * + * TODO setSavepoint is not supported + */ +/* public void testSetSavepoint_String() { + Statement st = null; + Statement st1 = null; + ResultSet rs1 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + Statement st2 = null; + ResultSet rs2 = null; + try { + Savepoint sp = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (Exception ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint("two"); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(sp1); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint("three"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint("four"); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + Savepoint sp = conn.setSavepoint("five"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } finally { + try { + rs1.close(); + st.close(); + st1.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Connection#rollback(Savepoint savepoint) + * + * TODO Savepoint is not supported + */ +/* public void testRollback_Savepoint() { + Statement st = null; + Statement st1 = null; + ResultSet rs1 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + Statement st2 = null; + ResultSet rs2 = null; + try { + Savepoint sp = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (Exception ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint("two"); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(sp1); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint("three"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint("four"); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.rollback(); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + Savepoint sp = conn.setSavepoint("five"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } finally { + try { + rs1.close(); + st.close(); + st1.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Connection#releaseSavepoint(Savepoint savepoint) + * + * TODO Savepoint is not supported + */ +/* public void testReleaseSavepoint_Savepoint() { + Statement st = null; + Statement st1 = null; + ResultSet rs1 = null; + try { + conn.setAutoCommit(false); + + st = conn.createStatement(); + st + .execute("insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');"); + st + .execute("insert into zoo (id, name, family) values (4, 'Orel', 'eagle');"); + + if (!conn.getAutoCommit()) { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + Statement st2 = null; + ResultSet rs2 = null; + try { + Savepoint sp = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.rollback(sp); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.releaseSavepoint(sp); + try { + conn.rollback(sp); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + conn.rollback(); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (Exception ee) { + } + } + + try { + Savepoint sp1 = conn.setSavepoint("one"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + Savepoint sp2 = conn.setSavepoint("two"); + st + .execute("insert into zoo (id, name, family) values (6, 'grach', 'rook');"); + conn.releaseSavepoint(sp1); + try { + conn.rollback(sp1); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + conn.commit(); + conn.rollback(sp2); + st2 = conn.createStatement(); + st2.execute("select * from zoo"); + rs2 = st2.getResultSet(); + assertEquals(4, getCount(rs2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + rs2.close(); + st2.close(); + } catch (SQLException ee) { + } + } + + } else { + st1 = conn.createStatement(); + st1.execute("select * from zoo"); + rs1 = st1.getResultSet(); + assertEquals(4, getCount(rs1)); + try { + Savepoint sp = conn.setSavepoint("five"); + st + .execute("insert into zoo (id, name, family) values (5, 'chayka', 'gull');"); + conn.releaseSavepoint(sp); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } finally { + try { + rs1.close(); + st.close(); + st1.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Connection#prepareStatement(String sql, int[] + * columnIndexes) + * + * TODO prepareStatement(String sql, int[] columnIndexes) is not + * supported + */ +/* public void testPrepareStatement_String_intArray() { + Statement st = null; + PreparedStatement prst1 = null; + PreparedStatement prst = null; + ResultSet rs = null; + ResultSet rs1 = null; + ResultSet rs4 = null; + ResultSet rs5 = null; + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + prst = conn.prepareStatement(insert, new int[] { 0, 1, 2 }); + prst.setInt(1, 8); + prst.setString(2, "Tuzik"); + prst.setString(3, "dog"); + + st = conn.createStatement(); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + prst.execute(); + st.execute("select * from zoo where family = 'dog'"); + rs1 = st.getResultSet(); + assertEquals(1, getCount(rs1)); + + rs4 = prst.getGeneratedKeys(); + assertEquals(0, getCount(rs4)); + + prst1 = conn.prepareStatement(insert, new int[] { 0, 1, 2, 10 }); + prst1.setInt(1, 5); + prst1.setString(2, "Layka"); + prst1.setString(3, "dog"); + + prst1.execute(); + + rs5 = prst1.getGeneratedKeys(); + assertEquals(0, getCount(rs5)); + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + rs1.close(); + rs4.close(); + rs5.close(); + st.close(); + prst1.close(); + prst.close(); + } catch (Exception ee) { + } + } + + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + conn.prepareStatement(insert, new int[] {}); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + conn.prepareStatement(insert, (int[]) null); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } +*/ + /** + * @test java.sql.Connection#prepareStatement(String sql, int resultSetType, + * int resultSetConcurrency) + */ +// TODO Crashes VM. Fix later. +/* public void testPrepareStatement_String_int_int() { + String query = "insert into zoo (id, name, family) values (?, ?, ?);"; + PreparedStatement st = null; + ResultSet rs = null; + try { + + st = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + st.execute("select id, name from zoo"); + rs = st.getResultSet(); + try { + rs.deleteRow(); + fail("Can delete row for READ_ONLY ResultSet"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.prepareStatement(query, + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("parrot", (rs.getString(1))); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); + st.execute("select name, family from zoo"); + rs = st.getResultSet(); + try { + rs.insertRow(); + rs.updateObject("family", "bird"); + rs.next(); + rs.previous(); + assertEquals("bird", (rs.getString(1))); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (SQLException ee) { + } + } + + try { + conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE, -1); + } catch (SQLException sqle) { + // expected + } + + try { + conn.prepareStatement(query, Integer.MIN_VALUE, + ResultSet.CONCUR_READ_ONLY); + } catch (SQLException sqle) { + // expected + } + } +*/ + /** + * @test java.sql.Connection#prepareStatement(String sql, int resultSetType, + * int resultSetConcurrency, int resultSetHoldability) + */ + // TODO Crashes VM. Fix later. +/* public void testPrepareStatement_String_int_int_int() { + String query = "insert into zoo (id, name, family) values (?, ?, ?);"; + PreparedStatement st = null; + ResultSet rs = null; + try { + st = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.HOLD_CURSORS_OVER_COMMIT); + st.setInt(1, 3); + st.setString(2, "Petya"); + st.setString(3, "Cock"); + st.execute("select id, name from zoo"); + rs = st.getResultSet(); + try { + rs.close(); + } catch (SQLException sqle) { + fail("Unexpected exception was thrown during closing ResultSet"); + } + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + //TODO ResultSet.CLOSE_CURSORS_AT_COMMIT is not supported + try { + st = conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + ResultSet.CLOSE_CURSORS_AT_COMMIT); + st.execute("select id, name from zoo"); + rs = st.getResultSet(); + try { + rs.close(); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException was thrown: " + e.getMessage()); + } finally { + try { + st.close(); + rs.close(); + } catch (SQLException ee) { + } + } + + try { + conn.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, -100); + fail("SQLException was not thrown"); + } catch (SQLException sqle) { + // expected + } + + } +*/ + /** + * @test java.sql.Connection#prepareStatement(String sql, String[] + * columnNames) + * + * TODO prepareStatement(String sql, String[] columnNames) method is + * not supported + */ + /* public void testPrepareStatement_String_StringArray() { + PreparedStatement prst = null; + PreparedStatement prst1 = null; + ResultSet rs = null; + ResultSet rs1 = null; + ResultSet rs4 = null; + ResultSet rs5 = null; + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + prst = conn.prepareStatement(insert, new String[] { "id", "name", + "family" }); + prst.setInt(1, 8); + prst.setString(2, "Tuzik"); + prst.setString(3, "dog"); + + Statement st = conn.createStatement(); + st.execute("select * from zoo"); + rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + prst.execute(); + st.execute("select * from zoo where family = 'dog'"); + rs1 = st.getResultSet(); + assertEquals(1, getCount(rs1)); + + rs4 = prst.getGeneratedKeys(); + assertEquals(0, getCount(rs4)); + + prst1 = conn.prepareStatement(insert, new String[] { "id", "name", "" }); + prst1.setInt(1, 5); + prst1.setString(2, "Layka"); + prst1.setString(3, "dog"); + + prst1.execute(); + + rs5 = prst1.getGeneratedKeys(); + assertEquals(0, getCount(rs5)); + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + rs1.close(); + rs4.close(); + rs5.close(); + prst.close(); + prst1.close(); + } catch (Exception ee) { + } + } + + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + conn.prepareStatement(insert, new String[] {}); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + + try { + String insert = "insert into zoo (id, name, family) values (?, ?, ?);"; + conn.prepareStatement(insert, (String[]) null); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } +*/ +} diff --git a/sql/src/test/java/tests/sql/PreparedStatementTest.java b/sql/src/test/java/tests/sql/PreparedStatementTest.java new file mode 100755 index 0000000..1e6b124 --- /dev/null +++ b/sql/src/test/java/tests/sql/PreparedStatementTest.java @@ -0,0 +1,2473 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import java.math.BigDecimal; +import java.sql.ParameterMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.sql.Date; +import java.util.Calendar; +import java.util.Locale; +import java.util.TimeZone; + +public class PreparedStatementTest extends SQLTest { + + String queryAllSelect = "select * from type"; + + String[] queries = { + "create table type (" + + + " BoolVal BOOLEAN," + " IntVal INT," + " LongVal LONG," + + " Bint BIGINT," + " Tint TINYINT," + " Sint SMALLINT," + + " Mint MEDIUMINT, " + + + " IntegerVal INTEGER, " + " RealVal REAL, " + + " DoubleVal DOUBLE, " + " FloatVal FLOAT, " + + " DecVal DECIMAL, " + + + " NumVal NUMERIC, " + " charStr CHAR(20), " + + " dateVal DATE, " + " timeVal TIME, " + " TS TIMESTAMP, " + + + + " DT DATETIME, " + " TBlob TINYBLOB, " + " BlobVal BLOB, " + + " MBlob MEDIUMBLOB, " + " LBlob LONGBLOB, " + + + " TText TINYTEXT, " + " TextVal TEXT, " + + " MText MEDIUMTEXT, " + " LText LONGTEXT " + ");", + + "insert into type (BoolVal, IntVal, LongVal, Bint, Tint, Sint, Mint," + + "IntegerVal, RealVal, DoubleVal, FloatVal, DecVal," + + "NumVal, charStr, dateVal, timeVal, TS," + + "DT, TBlob, BlobVal, MBlob, LBlob," + + "TText, TextVal, MText, LText" + + ") " + + "values (1, -1, 22, 2, 33," + + "3, 1, 2, 3.9, 23.2, 33.3, 44," + + "5, 'test string', '1799-05-26', '12:35:45', '2007-10-09 14:28:02.0'," + + "'1221-09-22 10:11:55', 1, 2, 3, 4," + + "'Test text message tiny', 'Test text message', 'Test text message medium', 'Test text message long');" }; + + public void createTables() { + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.execute(queries[i]); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } + + public void clearTables() { + Statement st = null; + try { + st = conn.createStatement(); + st.execute("drop table if exists type"); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#addBatch() + */ + public void testAddBatch() throws SQLException { + PreparedStatement ps = null; + try { + ps = conn + .prepareStatement("INSERT INTO zoo VALUES (3,'Tuzik', ?);"); + ps.addBatch("INSERT INTO zoo VALUES (?,'Burenka', ?); "); + ps.addBatch("INSERT INTO zoo VALUES (?,'Mashka','cat')"); + try { + ps.executeBatch(); + } catch (SQLException sqle) { + fail("SQLException is thrown for executeBatch()"); + } + ps.setString(1, "dog"); + Statement st = null; + try { + ps.executeBatch(); + st = conn.createStatement(); + st.execute("select * from zoo"); + ResultSet rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown for executeBatch()"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + + try { + ps = conn + .prepareStatement("INSERT INTO zoo VALUES (3,'Tuzik', ?);"); + ps.addBatch(""); + } catch (SQLException e) { + // expected + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + + try { + ps = conn + .prepareStatement("INSERT INTO zoo VALUES (3,'Tuzik', ?);"); + ps.addBatch(null); + } catch (SQLException e) { + // expected + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#execute() + */ + + // TODO Crashes VM. Fix later. + +/* public void testExecute() { + Statement st = null; + PreparedStatement ps = null; + try { + String query = "insert into zoo(id, family, name) values(?, ?, 'unknown animal')"; + ps = conn.prepareStatement(query); + ps.setInt(1, 3); + ps.setString(2, "No name"); + assertTrue(ps.execute()); + st = conn.createStatement(); + st.execute("select * from zoo"); + assertEquals(3, getCount(st.getResultSet())); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + ps.close(); + st.close(); + } catch(Exception ee) {} + } + + try { + String query = "update zoo set name='Masha', family=? where id=?;"; + ps = conn.prepareStatement(query); + ps.setString(1, "cat"); + ps.setInt(2, 2); + assertTrue(ps.execute()); + assertEquals(1, ps.getUpdateCount()); + st = conn.createStatement(); + st.execute("select family from zoo where id=2"); + ResultSet rs = st.getResultSet(); + rs.next(); assertEquals("cat", rs.getString(1)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + ps.close(); + st.close(); + } catch(Exception ee) {} + } + + try { + conn.createStatement().execute("drop table if exists hutch"); + String query = "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));"; + ps = conn.prepareStatement(query); + assertTrue(ps.execute()); + } catch(SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + + try { + String query = "select name, family from zoo where id = ?"; + ps = conn.prepareStatement(query); + ps.setInt(1, 1); + assertTrue(ps.execute()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + ps.close(); + } catch(Exception ee){} + } + + try { + String query = "select name, family from zoo where id = ?"; + ps = conn.prepareStatement(query); + ps.execute(); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + } +*/ + /* + * @test java.sql.PreparedStatement#executeQuery() + */ + + // TODO Crashes VM. Fix later. + /* public void testExecuteQuery() { + + String[] queries2 = { "update zoo set name='Masha', family='cat' where id=;", + "insert into hutch (id, animal_id, address) values (1, ?,'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (?, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=?" }; + + for (int i = 0; i < queries2.length; i++) { + PreparedStatement ps = null; + try { + ps = conn.prepareStatement(queries2[i]); + ps.executeQuery(); + fail("SQLException is not thrown for query: " + queries2[i]); + } catch(SQLException sqle) { + // expected + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + } + + String query = "select * from zoo where id = ?"; + PreparedStatement ps = null; + try { + ps = conn.prepareStatement(query); + ps.setInt(1, 1); + ResultSet rs = ps.executeQuery(); + rs.next(); + assertEquals(1, rs.getInt(1)); + assertEquals("Kesha", rs.getString(2)); + assertEquals("parrot", rs.getString(3)); + } catch (SQLException e) { + fail("SQLException is thrown for query"); + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + + try { + ps = conn.prepareStatement(query); + ps.setInt(1, 5); + ResultSet rs = ps.executeQuery(); + assertNotNull(rs); + assertFalse(rs.next()); + } catch(SQLException e) { + fail("SQLException is thrown for query"); + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + } +*/ + /** + * @test java.sql.PreparedStatement#executeUpdate() + */ + + // TODO Crashes VM. Fix later. +/* public void testExecuteUpdate() { + String[] queries1 = { "insert into hutch (id, animal_id, address) values (1, ?, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (?, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2" }; + + for (int i = 0; i < queries1.length; i++) { + PreparedStatement ps = null; + try { + ps = conn.prepareStatement(queries1[i]); + ps.executeUpdate(); + fail("SQLException is not thrown for query: " + queries1[i]); + } catch(SQLException sqle) { + // expected + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + } + + String query = "update zoo set name='Masha', family='cat' where id=?;"; + PreparedStatement ps = null; + try { + ps = conn.prepareStatement(query); + ps.setInt(1, 2); + int updateCount = ps.executeUpdate(); + assertEquals(1, updateCount); + ps.setInt(1, 1); + int updateCount1 = ps.executeUpdate(); + assertEquals(1, updateCount1); + } catch (SQLException e) { + fail("SQLException is thrown for query"); + } finally { + try { + ps.close(); + } catch(Exception ee) {} + } + } + */ + /** + * @test java.sql.PreparedStatement#getMetaData() + * + * TODO Doesn't pass on SQLite but according to Java docs: + * it is possible to invoke the method getMetaData on a + * PreparedStatement object rather than waiting to execute it. + */ + public void testGetMetaData() { + PreparedStatement ps = null; + try { + String query = "update zoo set name='Masha', family='cat' where id=?;"; + ps = conn.prepareStatement(query); + assertNull(ps.getMetaData()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } catch (Exception e) { + fail("Exception is thrown: " + e.toString()); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + + try { + String query = "select * from zoo where id = ?"; + ps = conn.prepareStatement(query); + ResultSetMetaData rsmd = ps.getMetaData(); + assertNotNull(rsmd); + assertEquals(3, rsmd.getColumnCount()); + assertEquals("id", rsmd.getColumnName(1)); + assertEquals("id", rsmd.getColumnName(1)); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#getParameterMetaData() + * TODO not supported exception + */ + /* public void testGetParameterMetaData() { + PreparedStatement ps = null; + try { + String query = "select * from zoo where id = ?"; + ps = conn.prepareStatement(query); + ParameterMetaData rsmd = ps.getParameterMetaData(); + assertNotNull(rsmd); + assertEquals(1, rsmd.getParameterCount()); + ps.setInt(1, 2); + ps.execute(); + ParameterMetaData rsmd1 = ps.getParameterMetaData(); + assertNotNull(rsmd1); + assertEquals(1, rsmd1.getParameterCount()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.toString()); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + + try { + String query = "select * from zoo where id = ?"; + ps = conn.prepareStatement(query); + ParameterMetaData rsmd = ps.getParameterMetaData(); + assertNotNull(rsmd); + assertEquals(1, rsmd.getParameterCount()); + ps.setInt(1, 2); + ps.execute(); + ParameterMetaData rsmd1 = ps.getParameterMetaData(); + assertNotNull(rsmd1); + assertEquals(1, rsmd1.getParameterCount()); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + + try { + String query = "select * from zoo where id = 1"; + ps = conn.prepareStatement(query); + ParameterMetaData rsmd = ps.getParameterMetaData(); + assertNotNull(rsmd); + assertEquals(0, rsmd.getParameterCount()); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + ps.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.PreparedStatement#clearParameters() + */ + /* + * TODO Crashes VM. Fix later. + * public void testClearParameters() { + * PreparedStatement ps = null; + * try { + * String query = "select * from zoo where id = ? and family=?"; + * ps = conn.prepareStatement(query); + * ps.setInt(1, 2); + * ps.setString(2, "dog"); + * ps.clearParameters(); + * try { ps.execute(); + * fail("SQLException is not thrown during execute method after calling clearParameters()"); + * } catch(SQLException sqle) { + * // expected + * } + * ps.setInt(1, 2); + * ps.clearParameters(); + * try { + * ps.execute(); + * fail("SQLException is not thrown during execute method after calling clearParameters()"); + * } catch(SQLException sqle) { + * // expected + * } + * ps.setInt(1, 2); + * ps.setString(2, "cat"); + * + * try { + * ps.execute(); + * } catch (SQLException sqle) { + * fail("SQLException is thrown during execute method after calling clearParameters() twice"); + * } + * } catch (SQLException e) { + * fail("SQLException is thrown"); + * } finally { + * try { + * ps.close(); + * } catch(SQLException ee) {} + * } + * } + */ + /** + * @test java.sql.PreparedStatement#setInt(int parameterIndex, int x) + */ + public void testSetInt() throws SQLException { + createTables(); + PreparedStatement ps = null; + Statement st = null; + try { + String query = "insert into type (IntVal) values (?);"; + ps = conn.prepareStatement(query); + try { + ps.setInt(1, Integer.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where IntVal=" + + Integer.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setInt(1, Integer.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where IntVal=" + + Integer.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setInt(2, Integer.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setInt(-2, 0); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setLong(int parameterIndex, long x) + */ + public void testSetLong() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (LongVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setLong(1, Long.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where LongVal=" + + Long.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setLong(1, Long.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where LongVal=" + + Long.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setLong(2, Long.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setLong(-2, 0); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + + } + + /** + * @test java.sql.PreparedStatement#setFloat(int parameterIndex, float x) + */ + public void testSetFloat() { + float value1 = 12345678.12345689f; + float value2 = -12345678.12345689f; + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (FloatVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setFloat(1, value1); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where FloatVal=" + value1); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setFloat(1, value2); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where FloatVal=" + value2); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setFloat(2, Float.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setFloat(-2, 0); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setDouble(int parameterIndex, double x) + */ + public void testSetDouble() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (DoubleVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setDouble(1, Double.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where DoubleVal=" + + Double.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setDouble(1, Double.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where DoubleVal=" + + Double.MIN_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setDouble(2, Double.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setDouble(-2, 0); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + + } + + /** + * @test java.sql.PreparedStatement#setString(int parameterIndex, String x) + */ + public void testSetString_charField() { + createTables(); + PreparedStatement ps = null; + try { + String str = "test^text$test%"; + String query = "insert into type (charStr) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setString(1, str); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where charStr='" + str + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, ""); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where charStr=''"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(1, " "); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where charStr=' '"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(-2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(1, " test & text * test % text * test ^ text "); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } + + try { + ps.setString(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setString(int parameterIndex, String x) + */ + public void testSetString_tinyTextField() { + createTables(); + PreparedStatement ps = null; + try { + String str = "test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test"; + String query = "insert into type (TText) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setString(1, str); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where TText='" + str + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, ""); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where TText=''"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(1, " "); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where TText=' '"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(-2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString( + 1, + "test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test*test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test-test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test+test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test?test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test#test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test "); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } + + try { + ps.setString(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setString(int parameterIndex, String x) + */ + public void testSetString_textField() { + createTables(); + PreparedStatement ps = null; + try { + String str = "test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test"; + String query = "insert into type (TextVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setString(1, str); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where TextVal='" + str + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, ""); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where TextVal=''"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(1, " "); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where TextVal=' '"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setString(2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(-2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + String longString = " test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/"; + for (int i = 0; i < 10; i++) { + longString += longString; + } + ps.setString(1, longString); + ps.execute(); + + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } + + try { + ps.setString(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setString(int parameterIndex, String x) + */ + public void testSetString_mediumTextField() { + createTables(); + PreparedStatement ps = null; + try { + String str = "test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test"; + String query = "insert into type (MText) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setString(1, str); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where MText='" + str + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, ""); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where MText=''"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, " "); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where MText=' '"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(-2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setString(int parameterIndex, String x) + */ + public void testSetString_longTextField() { + createTables(); + PreparedStatement ps = null; + try { + String str = "test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test/test^text$test%test(text)test@text5test~test^text$test%test(text)test@text5test"; + String query = "insert into type (LText) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setString(1, str); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where LText='" + str + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, ""); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where LText=''"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(1, " "); + ps.execute(); + st = conn.createStatement(); + st + .execute("select * from type where LText=' '"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setString(2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(-2, "test text"); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setString(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setShort(int parameterIndex, short x) + */ + public void testSetShort() { + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + PreparedStatement ps2 = null; + try { + String query = "insert into type (Sint) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setShort(1, Short.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where Sint=" + Short.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setShort(1, Short.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where Sint=" + Short.MIN_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setShort(2, Short.MAX_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setShort(-2, Short.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + String query1 = "insert type(Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + try { + ps1.setShort(1, Short.MAX_VALUE); + ps1.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + String query2 = "insert into type (IntVal) values (?);"; + ps2 = conn.prepareStatement(query2); + try { + ps2.setShort(1, Short.MAX_VALUE); + ps2.execute(); + st = conn.createStatement(); + st + .execute("select * from type where IntVal=" + + Short.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + ps2.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setBoolean(int parameterIndex, boolean + * x) + */ + public void testSetBoolean() { + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (BoolVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setBoolean(1, false); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where BoolVal = 0"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setBoolean(1, true); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where BoolVal= 1"); + ResultSet rs = st.getResultSet(); + assertEquals(2, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setBoolean(2, true); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setBoolean(-2, false); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + String query1 = "insert into type (Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + try { + ps1.setBoolean(1, true); + ps1.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setByte(int parameterIndex, byte x) + */ + public void testSetByte() { + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (Tint) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setByte(1, Byte.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where Tint=" + Byte.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setByte(1, Byte.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where Tint=" + Byte.MIN_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setByte(2, Byte.MAX_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setByte(-2, Byte.MIN_VALUE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + String query1 = "insert into type (IntVal) values (?);"; + ps1 = conn.prepareStatement(query1); + try { + ps1.setByte(1, Byte.MAX_VALUE); + ps1.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setBytes(int parameterIndex, byte[] x) + */ + public void testSetBytes() { + + byte[] bytesArray = {1, 0}; + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (LBlob) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setBytes(1, bytesArray); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + ps.setBytes(2, bytesArray); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setBytes(-2, bytesArray); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (TBlob) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps.setBytes(1, bytesArray); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setBigDecimal(int parameterIndex, + * BigDecimal x) + */ + public void testSetBigDecimal() { + + BigDecimal bd = new BigDecimal("50"); + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (DecVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setBigDecimal(1, bd); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where DecVal=" + bd); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + ps.setBigDecimal(2, bd); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setBigDecimal(-2, bd); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setBigDecimal(1, bd); + ps1.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setDate(int parameterIndex, Date x) + */ + public void testSetDate_int_Date() { + + Date[] dates = { new Date(1799, 05, 26), new Date(Integer.MAX_VALUE), + new Date(123456789) }; + + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (dateVal) values (?);"; + ps = conn.prepareStatement(query); + + for (int i = 0; i < dates.length; i++) { + Statement st = null; + try { + ps.setDate(1, dates[i]); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where dateVal='" + + dates[i].toString() + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + try { + ps.setDate(2, dates[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setDate(-2, dates[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert type(Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setDate(1, dates[0]); + ps1.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setDate(int parameterIndex, Date x, + * Calendar cal) + */ + public void testSetDate_int_Date_Calendar() { + + Calendar[] cals = { Calendar.getInstance(), + Calendar.getInstance(Locale.GERMANY), + Calendar.getInstance(TimeZone.getDefault()) }; + + Date[] dates = { new Date(1799, 05, 26), new Date(Integer.MAX_VALUE), + new Date(123456789) }; + + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (dateVal) values (?);"; + ps = conn.prepareStatement(query); + + for (int i = 0; i < dates.length; i++) { + Statement st = null; + try { + ps.setDate(1, dates[i], cals[i]); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where dateVal='" + + dates[i].toString() + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + try { + ps.setDate(2, dates[0], cals[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setDate(-2, dates[0], cals[1]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setDate(1, dates[0], cals[2]); + ps1.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown"); + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setNull(int parameterIndex, int sqlType) + * + * this test doesn't passed on RI + */ + public void testSetNull_int_int() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (BoolVal, IntVal) values ('true', ?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setNull(1, Types.INTEGER); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (BoolVal, LongVal) values (true, ?);"; + ps = conn.prepareStatement(query); + + try { + ps.setNull(1, Types.BIGINT); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + //expected + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (BoolVal, DecVal) values ('true', ?)"; + ps = conn.prepareStatement(query); + + try { + ps.setNull(1, Types.DECIMAL); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (BoolVal, dateVal) values (true, ?);"; + ps = conn.prepareStatement(query); + + try { + ps.setNull(1, Types.DATE); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + //expected + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (BoolVal, BlobVal) values (true, ?);"; + ps = conn.prepareStatement(query); + + try { + ps.setNull(1, Types.BLOB); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + //expected + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (BoolVal, TextVal) values (true, ?);"; + ps = conn.prepareStatement(query); + + try { + ps.setNull(1, Types.CHAR); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + //expected + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setObject(int parameterIndex, Object x) + * + * this test doesn't pass on RI + */ + public void testSetObject_int_Object() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (IntVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setObject(1, Integer.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where IntVal=" + + Integer.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (LongVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, "test text"); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where LongVal='test text';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + query = "insert into type (DecVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, new Object()); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is not thrown"); + } + + query = "insert into type (dateVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, new Date(123456789)); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where dateVal='" + + new Date(123456789) + "';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + // this sub test doesn't pass on RI + query = "insert into type (BlobVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, null); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setObject(int parameterIndex, Object x, + * int targetSqlType) + * + * this test doesn't pass on RI + */ + public void testSetObject_int_Object_int() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type(IntVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setObject(1, Integer.MAX_VALUE, Types.INTEGER); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where IntVal=" + + Integer.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (LongVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, "test text", Types.CHAR); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where LongVal='test text';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (DecVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, new Object(), Types.DECIMAL); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + + query = "insert into type (dateVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, new Date(123456789), Types.DATE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where dateVal='" + + new Date(123456789) + "';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + // this sub test doesn't pass on RI + query = "insert into type (BlobVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, "", Types.BLOB); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setObject(int parameterIndex, Object x, + * int targetSqlType, int scale) + * + * this test doesn't pass on RI + */ + public void testSetObject_int_Object_int_int() { + createTables(); + PreparedStatement ps = null; + try { + String query = "insert into type (IntVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + try { + ps.setObject(1, Integer.MAX_VALUE, Types.INTEGER, + Integer.MAX_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where IntVal=" + + Integer.MAX_VALUE); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (LongVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, "test text", Types.CHAR, Integer.MIN_VALUE); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where LongVal='test text';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + query = "insert into type (DecVal) values (?);"; + ps = conn.prepareStatement(query); + BigDecimal bd2 = new BigDecimal("12.21"); + + try { + ps.setObject(1, bd2, Types.DECIMAL, 2); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + + query = "insert into type (dateVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, new Date(123456789), Types.DATE, -1); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where dateVal='" + + new Date(123456789) + "';"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + // this sub test doesn't pass on RI + query = "insert into type(BlobVal) values (?);"; + ps = conn.prepareStatement(query); + + try { + ps.setObject(1, "", Types.BLOB, 0); + ps.execute(); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setTime(int parameterIndex, Time x) + */ + public void testSetTimeint_Time() { + + Time[] times = { new Time(24, 25, 26), new Time(Integer.MAX_VALUE), + new Time(123456789) }; + + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (timeVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + for (int i = 0; i < times.length; i++) { + try { + ps.setTime(1, times[i]); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where timeVal='" + + times[i].toString() + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } + + try { + ps.setTime(2, times[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setTime(-2, times[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (Tint) values (?)"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setTime(1, times[0]); + ps1.execute(); + + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setTime(int parameterIndex, Time x, + * Calendar cal) + */ + public void testSetTime_int_Time_Calendar() { + + Calendar[] cals = { Calendar.getInstance(), + Calendar.getInstance(Locale.GERMANY), + Calendar.getInstance(TimeZone.getDefault()) }; + + Time[] times = { new Time(24, 25, 26), new Time(Integer.MAX_VALUE), + new Time(123456789) }; + + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (timeVal) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + for (int i = 0; i < times.length; i++) { + try { + ps.setTime(1, times[i], cals[i]); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where timeVal='" + + times[i].toString() + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } + + try { + ps.setTime(2, times[0], cals[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setTime(-2, times[0], cals[1]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setTime(1, times[0], cals[2]); + ps1.execute(); + + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.PreparedStatement#setTimestamp(int parameterIndex, + * Timestamp x) + */ + public void testSetTimestamp_int_Timestamp() { + + Timestamp[] timestamps = { new Timestamp(2007, 10, 17, 19, 06, 50, 23), + new Timestamp(123) }; + + createTables(); + PreparedStatement ps = null; + PreparedStatement ps1 = null; + try { + String query = "insert into type (TS) values (?);"; + ps = conn.prepareStatement(query); + Statement st = null; + for (int i = 0; i < timestamps.length; i++) { + try { + ps.setTimestamp(1, timestamps[i]); + ps.execute(); + st = conn.createStatement(); + st.execute("select * from type where TS='" + + timestamps[i].toString() + "'"); + ResultSet rs = st.getResultSet(); + assertEquals(1, getCount(rs)); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + try { + ps.setTimestamp(2, timestamps[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + try { + ps.setTimestamp(-2, timestamps[0]); + ps.execute(); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + String query1 = "insert into type (Tint) values (?);"; + ps1 = conn.prepareStatement(query1); + + try { + ps1.setTimestamp(1, timestamps[0]); + ps1.execute(); + + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + clearTables(); + ps.close(); + ps1.close(); + } catch (Exception ee) { + } + } + } +} diff --git a/sql/src/test/java/tests/sql/ResultSetMetaDataTest.java b/sql/src/test/java/tests/sql/ResultSetMetaDataTest.java new file mode 100755 index 0000000..1f9483b --- /dev/null +++ b/sql/src/test/java/tests/sql/ResultSetMetaDataTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; + +public class ResultSetMetaDataTest extends SQLTest { + + ResultSetMetaData rsmd = null; + Statement st = null; + ResultSet rs = null; + + public void setUp() { + super.setUp(); + try { + String query = "select * from zoo"; + st = conn.createStatement(); + st.execute(query); + rs = st.getResultSet(); + rsmd = rs.getMetaData(); + } catch (SQLException e) { + fail("Couldn't get ResultSetMetaData object"); + } + } + + public void tearDown() { + super.tearDown(); + try { + rs.close(); + st.close(); + } catch (SQLException e) { + fail("Couldn't close Statement object"); + } + } + + /** + * @test java.sql.ResultSetMetaData#getCatalogName(int column) + */ + public void testGetCatalogName() throws SQLException { + try { + assertNull(rsmd.getCatalogName(0)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnClassName(int column) + */ + public void testGetColumnClassName() { + try { + assertNotNull(rsmd); + assertEquals(Short.class.getName(), rsmd.getColumnClassName(1)); + assertEquals(String.class.getName(), rsmd.getColumnClassName(2)); + assertEquals(String.class.getName(), rsmd.getColumnClassName(3)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + + try { + String name = rsmd.getColumnClassName(-1); + assertNull(name); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + + try { + String name = rsmd.getColumnClassName(4); + assertNull(name); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnCount() + */ + public void testGetColumnCount() { + try { + assertEquals(3, rsmd.getColumnCount()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnLabel(int column) + */ + public void testGetColumnLabel() { + String[] labels = { "zoo.id", "zoo.name", "zoo.family" }; + try { + for (int i = 0; i < rsmd.getColumnCount(); i++) { + String label = rsmd.getColumnLabel(i + 1); + assertEquals(labels[i], label); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnName(int column) + */ + public void testGetColumnName() { + String[] labels = { "zoo.id", "zoo.name", "zoo.family" }; + try { + for (int i = 0; i < rsmd.getColumnCount(); i++) { + String label = rsmd.getColumnLabel(i + 1); + assertEquals(labels[i], label); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + + try { + String label = rsmd.getColumnLabel(-1); + assertNull(label); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + + try { + String label = rsmd.getColumnLabel(5); + assertNull(label); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnType(int column) + */ + public void testGetColumnType() { + int[] types = { Types.SMALLINT, Types.VARCHAR, Types.VARCHAR}; + try { + for (int i = 0; i < rsmd.getColumnCount(); i++) { + int type = rsmd.getColumnType(i + 1); + assertEquals(types[i], type); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + + try { + rsmd.getColumnType(-1); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + try { + rsmd.getColumnType(5); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + } + + /** + * @test java.sql.ResultSetMetaData#getColumnTypeName(int column) + */ + public void testGetColumnTypeName() { + try { + assertEquals("smallint", rsmd.getColumnTypeName(1)); + assertEquals("varchar", rsmd.getColumnTypeName(2)); + assertEquals("varchar", rsmd.getColumnTypeName(3)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + + try { + rsmd.getColumnTypeName(-1); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + try { + rsmd.getColumnTypeName(5); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } + } + + /** + * @test java.sql.ResultSetMetaData#getTableName(int column) + */ + public void testGetTableName() { + try { + assertEquals("zoo", rsmd.getTableName(1)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + Statement st1 = null; + ResultSet rs1 = null; + try { + String[] queries = { + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "select name, animal_id from hutch, zoo where zoo.id = 1" }; + st1 = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st1.execute(queries[i]); + } + rs1 = st1.getResultSet(); + ResultSetMetaData rsmd1 = rs1.getMetaData(); + assertEquals("zoo", rsmd1.getTableName(1)); + assertEquals("hutch", rsmd1.getTableName(2)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs1.close(); + st1.execute("drop table ifexists hutch"); + st1.close(); + + } catch (SQLException sqle) { + } + } + + try { + String name = rsmd.getTableName(-1); + assertNull(name); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + try { + String name = rsmd.getTableName(5); + assertNull(name); + } catch (SQLException e) { + fail("SQLException is thrown"); + } + } +} diff --git a/sql/src/test/java/tests/sql/SQLTest.java b/sql/src/test/java/tests/sql/SQLTest.java new file mode 100755 index 0000000..08ae350 --- /dev/null +++ b/sql/src/test/java/tests/sql/SQLTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import tests.support.Support_SQL; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class SQLTest extends TestCase { + static Connection conn; + + public void setUp() { + getSQLiteConnection(); + createZoo(); + } + + private final File dbFile = new File("sqliteTest2.db"); + + protected void getSQLiteConnection() { + try { + Class.forName("SQLite.JDBCDriver").newInstance(); + if(dbFile.exists()) dbFile.delete(); + conn = DriverManager.getConnection("jdbc:sqlite:/" + + dbFile.getName()); + } catch (Exception e) { + fail("Exception: " + e.toString()); + } + } + + public void tearDown() { + Statement st = null; + try { + st = conn.createStatement(); + st.execute("drop table if exists zoo"); + + } catch (SQLException e) { + fail("Couldn't drop table: " + e.getMessage()); + } finally { + try { + st.close(); + conn.close(); + } catch(SQLException ee) {} + } + } + + public void createZoo() { + + String[] queries = { + "create table zoo(id smallint, name varchar(10), family varchar(10))", + "insert into zoo values (1, 'Kesha', 'parrot')", + "insert into zoo values (2, 'Yasha', 'sparrow')" }; + + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.execute(queries[i]); + } + } catch (SQLException e) { + e.printStackTrace(); + fail("Unexpected exception: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) {} + } + } + + public void createProcedure() { + String proc = "CREATE PROCEDURE welcomeAnimal (IN parameter1 integer, IN parameter2 char(20), IN parameter3 char(20)) " + + " BEGIN " + + " INSERT INTO zoo(id, name, family) VALUES (parameter1, parameter2, parameter3); " + + "SELECT * FROM zoo;" + " END;"; + Statement st = null; + try { + st = conn.createStatement(); + st.execute("DROP PROCEDURE IF EXISTS welcomeAnimal"); + st.execute(proc); + } catch (SQLException e) { + fail("Unexpected exception: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) {} + } + } + + public int getCount(ResultSet rs) { + int count = 0; + try { + while (rs.next()) { + count++; + } + } catch (SQLException e) { + fail("SQLException is thrown"); + } + return count; + } +} diff --git a/sql/src/test/java/tests/sql/StatementTest.java b/sql/src/test/java/tests/sql/StatementTest.java new file mode 100755 index 0000000..fd1002e --- /dev/null +++ b/sql/src/test/java/tests/sql/StatementTest.java @@ -0,0 +1,955 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.sql; + +import java.sql.BatchUpdateException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.Statement; +import java.util.Vector; + +public class StatementTest extends SQLTest { + + /** + * @test java.sql.Statement#addBatch(String) + */ + public void testAddBatch() throws SQLException { + + Statement st = null; + try { + st = conn.createStatement(); + st.addBatch("INSERT INTO zoo VALUES (3,'Tuzik','dog')"); + st.addBatch("INSERT INTO zoo VALUES (4,'Mashka','cat')"); + + int[] updateCounts = st.executeBatch(); + assertEquals(2, updateCounts.length); + assertEquals(1, updateCounts[0]); + assertEquals(1, updateCounts[1]); + + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.addBatch(""); + st.executeBatch(); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.addBatch(null); + st.executeBatch(); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#clearWarnings() + */ + public void testClearWarnings() { + Statement st = null; + try { + st = conn.createStatement(); + st.execute("select animals from zoo"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + try { + st = conn.createStatement(); + st.clearWarnings(); + SQLWarning w = st.getWarnings(); + assertNull(w); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#getWarnings() + * + * TODO getWarnings is not supported + */ +/* public void testGetWarnings() { + + Statement st = null; + int errorCode1 = -1; + int errorCode2 = -1; + + try { + st = conn.createStatement(); + st.execute("select animals from zoooo"); + } catch (SQLException e) { + // expected + errorCode1 = e.getErrorCode(); + } + try { + SQLWarning wrs = st.getWarnings(); + assertNull(wrs); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + try { + st.execute("select horse from zoooooo"); + } catch (SQLException e) { + // expected + errorCode2 = e.getErrorCode(); + } + + try { + SQLWarning wrs = st.getWarnings(); + assertEquals(errorCode1, wrs.getErrorCode()); + assertNotNull(wrs.getNextWarning()); + assertEquals(errorCode2, wrs.getErrorCode()); + } catch (Exception e) { + fail("Unexpected Exception: " + e.getMessage()); + } + + try { + st.close(); + } catch (SQLException ee) { + } + + } +*/ + /** + * @test java.sql.Statement#clearBatch(String) + */ + public void testClearBatch() throws SQLException { + + Statement st = null; + + try { + st = conn.createStatement(); + st.addBatch("INSERT INTO zoo VALUES (3,'Tuzik','dog'); "); + st.addBatch("INSERT INTO zoo VALUES (4,'Mashka','cat')"); + + int[] updateCounts = st.executeBatch(); + assertEquals(2, updateCounts.length); + assertEquals(1, updateCounts[0]); + assertEquals(1, updateCounts[1]); + + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.addBatch(""); + st.executeBatch(); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.addBatch(null); + st.executeBatch(); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#execute(String sql) + * + * TODO not pass on SQLite and RI. + * + */ + public void testExecute() throws SQLException { + + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "select animal_id, address from hutch where animal_id=1;", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + boolean[] results = {true, true, true, true, true, true, true, + true, true}; + + for (int i = 0; i < queries.length; i++) { + Statement st = null; + try { + st = conn.createStatement(); + boolean res = st.execute(queries[i]); + assertEquals(results[i], res); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } + + String[] inc_queries = { + "update zoo_zoo set name='Masha', family='cat' where id=5;", + "drop table hutchNO", + "insert into hutch (id, animal_id, address) values (1, 2, 10);", + "select animal_id, from hutch where animal_id=1;", + "drop view address;", "drop table hutch;", "", null }; + + for (int i = 0; i < inc_queries.length; i++) { + Statement st = null; + try { + st = conn.createStatement(); + st.execute(inc_queries[i]); + fail("SQLException is not thrown for query: " + inc_queries[i]); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + } + + /** + * @test java.sql.Statement#execute(String sql, int autoGeneratedKeys) + * TODO not supported + */ + /* public void testExecute_String_int() { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "select animal_id, address from hutch where animal_id=1;", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + for (int i = 0; i < queries.length; i++) { + Statement st = null; + try { + st = conn.createStatement(); + st.execute(queries[i], Statement.NO_GENERATED_KEYS); + ResultSet rs = st.getGeneratedKeys(); + assertFalse(rs.next()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + } +*/ + /** + * @test java.sql.Statement#getConnection() + */ + public void testGetConnection() { + Statement st = null; + try { + st = conn.createStatement(); + assertSame(conn, st.getConnection()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#getFetchDirection() + */ + public void testGetFetchDirection() { + Statement st = null; + try { + st = conn.createStatement(); + assertEquals(ResultSet.FETCH_UNKNOWN, st.getFetchDirection()); + } catch (SQLException e) { + fail("SQLException is thrown" + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#setFetchDirection() + * TODO not supported + */ +/* public void testSetFetchDirection() { + Statement st = null; + try { + st = conn.createStatement(); + st.setFetchDirection(ResultSet.FETCH_FORWARD); + assertEquals(ResultSet.FETCH_FORWARD, st.getFetchDirection()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + try { + st = conn.createStatement(); + st.setFetchDirection(-1); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.setFetchDirection(100); + fail("SQLException is not thrown"); + } catch (SQLException e) { + // expected + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#getFetchSize() + */ + public void testGetFetchSize() { + Statement st = null; + try { + st = conn.createStatement(); + assertEquals(1, st.getFetchSize()); + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#setFetchSize() + * TODO not supported + */ +/* public void testSetFetchSize() { + Statement st = null; + try { + st = conn.createStatement(); + int rows = 100; + for (int i = 0; i < rows; i++) { + try { + st.setFetchSize(i); + assertEquals(i, st.getFetchSize()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.toString()); + } + } + try { + st.setFetchSize(-1); + fail("SQLException is not thrown"); + } catch (SQLException sqle) { + // expected + } + + } catch (SQLException e) { + fail("SQLException is thrown"); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#setMaxFieldSize(int max) + * TODO not supported + */ +/* public void testSetMaxFieldSize() { + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 0; i < 300; i += 50) { + try { + st.setMaxFieldSize(i); + assertEquals(i, st.getMaxFieldSize()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } + try { + st.setMaxFieldSize(-1); + fail("SQLException isn't thrown"); + } catch (SQLException sqle) { + // expecteds + } + } catch (SQLException e) { + fail("Can't create statement, SQLException is thrown: " + + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#getMaxFieldSize() + * TODO not supported + */ +/* public void testGetMaxFieldSize() { + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 200; i < 500; i += 50) { + try { + st.setMaxFieldSize(i); + assertEquals(i, st.getMaxFieldSize()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } + } catch (SQLException e) { + fail("Can't create statement, SQLException is thrown: " + + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#setMaxRows(int max) + * TODO not supported + */ + /* public void testSetMaxRows() { + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 0; i < 300; i += 50) { + try { + st.setMaxRows(i); + assertEquals(i, st.getMaxRows()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } + try { + st.setMaxRows(-1); + fail("SQLException isn't thrown"); + } catch (SQLException sqle) { + // expecteds + } + } catch (SQLException e) { + fail("Can't create statement, SQLException is thrown: " + + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#getMaxRows() + * TODO not supported + */ +/* public void testGetMaxRows() { + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 200; i < 500; i += 50) { + try { + st.setMaxRows(i); + assertEquals(i, st.getMaxRows()); + } catch (SQLException sqle) { + fail("SQLException is thrown: " + sqle.getMessage()); + } + } + } catch (SQLException e) { + fail("Can't create statement, SQLException is thrown: " + + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#close() + * TODO not passed but according to Java Docs + */ + public void testClose() { + Statement st = null; + try { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "insert into zoo (id, name, family) values (3, 'Vorobey', 'sparrow');", + "insert into zoo (id, name, family) values (4, 'Slon', 'elephant');", + "select * from zoo" }; + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.execute(queries[i]); + } + assertNotNull(st.getResultSet()); + st.close(); + assertNull(st.getResultSet()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#execute(String sql, int[] columnIndexes) + * TODO not supported + */ +/* public void testExecute_String_intArray() { + Statement st = null; + try { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "insert zoo(id, name, family) values (3, 'Vorobey', 'sparrow');", + "insert zoo(id, name, family) values (4, 'Slon', 'elephant');", + "select * from zoo" }; + Vector<int[]> array = new Vector<int[]>(); + array.addElement(null); + array.addElement(new int[] { 1, 2, 3 }); + array.addElement(new int[] { 1, 2, 10, 100 }); + array.addElement(new int[] {}); + + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.execute(queries[i], (int[]) array.elementAt(i)); + } + assertNotNull(st.getResultSet()); + st.close(); + assertNull(st.getResultSet()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#execute(String sql, String[] columnNames) + */ +/* public void testExecute_String_StringArray() { + Statement st = null; + try { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "insert zoo(id, name, family) values (3, 'Vorobey', 'sparrow');", + "insert zoo(id, name, family) values (4, 'Slon', 'elephant');", + "select * from zoo" }; + Vector<String[]> array = new Vector<String[]>(); + array.addElement(null); + array.addElement(new String[] { "", "", "", "", "", "", "", "" }); + array.addElement(new String[] { "field 1", "", "field2" }); + array.addElement(new String[] { "id", "family", "name" }); + + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.execute(queries[i], (String[]) array.elementAt(i)); + } + assertNotNull(st.getResultSet()); + st.close(); + assertNull(st.getResultSet()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#executeBatch() + */ + public void testExecuteBatch() { + + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + int[] result = { 1, 1, 1, 1, 1, 1, 1, 1 }; + Statement st = null; + try { + st = conn.createStatement(); + assertEquals(0, st.executeBatch().length); + for (int i = 0; i < queries.length; i++) { + st.addBatch(queries[i]); + } + int[] resArray = st.executeBatch(); + assertTrue(java.util.Arrays.equals(result, resArray)); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + + try { + st = conn.createStatement(); + st.addBatch("select * from zoo"); + st.executeBatch(); + } catch (BatchUpdateException bue) { + fail("BatchUpdateException is thrown: " + bue.toString()); + } catch (SQLException sqle) { + fail("Unknown SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } + + /** + * @test java.sql.Statement#executeQuery(String sql) + */ + public void testExecuteQuery_String() { + + String[] queries1 = { "select * from zoo", + "select name, family from zoo where id = 1" }; + + String[] queries2 = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;", "select from zoo" }; + + Statement st = null; + + try { + st = conn.createStatement(); + for (int i = 0; i < queries1.length; i++) { + try { + ResultSet rs = st.executeQuery(queries1[i]); + assertNotNull(rs); + } catch (SQLException sqle) { + fail("SQLException is thrown for query: " + queries1[i]); + } + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + try { + st = conn.createStatement(); + for (int i = 0; i < queries2.length; i++) { + try { + st.executeQuery(queries2[i]); + fail("SQLException is not thrown for query: " + queries2[i]); + } catch (SQLException sqle) { + // expected + } + } + } catch (SQLException sqle) { + fail("Unknown SQLException is thrown: " + sqle.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + + } + + /** + * @test java.sql.Statement#executeUpdate(String sql) + */ + public void testExecuteUpdate_String() { + + String[] queries1 = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + String[] queries2 = { "select * from zoo", + "select name, family from zoo where id = 1" }; + + Statement st = null; + try { + st = conn.createStatement(); + for (int i = 0; i < queries1.length; i++) { + try { + st.executeUpdate(queries1[i]); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } + } + + for (int i = 0; i < queries2.length; i++) { + try { + st.executeUpdate(queries2[i]); + fail("SQLException is not thrown for query: " + queries2[i]); + } catch (SQLException e) { + // expected + } + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (Exception ee) { + } + } + } + + /** + * @test java.sql.Statement#executeUpdate(String sql, int[] columnIndexes) + * + * TODO executeUpdate(String sql, int[] columnIndexes) is not supported + */ +/* public void testExecuteUpdate_String_intArray() { + Statement st = null; + try { + String[] queries1 = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + Vector<int[]> array = new Vector<int[]>(); + array.addElement(null); + array.addElement(new int[] { 1, 2, 3 }); + array.addElement(new int[] { 1, 2, 10, 100 }); + array.addElement(new int[] {}); + array.addElement(new int[] { 100, 200 }); + array.addElement(new int[] { -1, 0 }); + array.addElement(new int[] { 0, 0, 0, 1, 2, 3 }); + array.addElement(new int[] { -100, -200 }); + + st = conn.createStatement(); + for (int i = 0; i < queries1.length; i++) { + st.executeUpdate(queries1[i], (int[]) array.elementAt(i)); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#executeUpdate(String sql, int autoGeneratedKeys) + * + * TODO executeUpdate(String sql, int autoGeneratedKeys) is not supported + */ +/* public void testExecuteUpdate_String_int() { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "select animal_id, address from hutch where animal_id=1;", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + for (int i = 0; i < queries.length; i++) { + Statement st = null; + ResultSet rs = null; + try { + st = conn.createStatement(); + st.executeUpdate(queries[i], Statement.NO_GENERATED_KEYS); + rs = st.getGeneratedKeys(); + assertFalse(rs.next()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + rs.close(); + st.close(); + } catch (Exception ee) { + } + } + } + } +*/ + /** + * @test java.sql.Statement#executeUpdate(String sql, String[] columnNames) + * + * TODO executeUpdate(String sql, String[] columnNames) is not supported + */ +/* public void testExecuteUpdate_String_StringArray() { + Statement st = null; + try { + String[] queries = { + "update zoo set name='Masha', family='cat' where id=2;", + "drop table if exists hutch", + "create table hutch (id integer not null, animal_id integer, address char(20), primary key (id));", + "insert into hutch (id, animal_id, address) values (1, 2, 'Birds-house, 1');", + "insert into hutch (id, animal_id, address) values (2, 1, 'Horse-house, 5');", + "create view address as select address from hutch where animal_id=2", + "drop view address;", "drop table hutch;" }; + + Vector<String[]> array = new Vector<String[]>(); + array.addElement(null); + array.addElement(new String[] { "", "", "", "", "", "", "", "" }); + array.addElement(new String[] { "field 1", "", "field2" }); + array.addElement(new String[] { "id", "family", "name" }); + array + .addElement(new String[] { "id", null, "family", null, + "name" }); + array.addElement(new String[] { "id", " ", "name" }); + array.addElement(new String[] { null, null, null, null }); + array.addElement(new String[] { " ", "123 21", "~!@#$%^&*()_+ ", + null }); + + st = conn.createStatement(); + for (int i = 0; i < queries.length; i++) { + st.executeUpdate(queries[i], (String[]) array.elementAt(i)); + } + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +*/ + /** + * @test java.sql.Statement#getUpdateCount() + */ + public void testGetUpdateCount() { + Statement st = null; + try { + String query = "update zoo set name='Masha', family='cat' where id=2;"; + st = conn.createStatement(); + assertEquals(0, st.getUpdateCount()); + st.executeUpdate(query); + assertEquals(1, st.getUpdateCount()); + query = "update zoo set name='Masha', family='cat' where id=5;"; + st.executeUpdate(query); + assertEquals(0, st.getUpdateCount()); + } catch (SQLException e) { + fail("SQLException is thrown: " + e.getMessage()); + } finally { + try { + st.close(); + } catch (SQLException ee) { + } + } + } +} diff --git a/sql/src/test/java/tests/support/DatabaseCreator.java b/sql/src/test/java/tests/support/DatabaseCreator.java new file mode 100755 index 0000000..8d73c45 --- /dev/null +++ b/sql/src/test/java/tests/support/DatabaseCreator.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.support; + +import java.sql.Connection; +import java.sql.Date; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; + +public class DatabaseCreator { + public static final int defaultInt = 2; + + public static final String defaultString = "string"; + + public static final String defaultCharacter = "chr"; + + public static final double defaultDouble = 0.1; + + public static final String TEST_TABLE1 = "table1"; + + public static final String TEST_TABLE2 = "table2"; + + public static final String TEST_TABLE3 = "table3"; + + public static final String TEST_TABLE4 = "table4"; + + public static final String SALESPEOPLE_TABLE = "Salespeople"; + + public static final String CUSTOMERS_TABLE = "Customers"; + + public static final String ORDERS_TABLE = "Orders"; + + public static final String PARENT_TABLE = "test_names"; + + public static final String FKSTRICT_TABLE = "test_strict"; + + public static final String FKCASCADE_TABLE = "test_cascade"; + + public static final String TEST_TABLE5 = "test"; + + public static final String SIMPLE_TABLE1 = "simple_table1"; + + public static final String SIMPLE_TABLE2 = "simple_table2"; + + public static final String SIMPLE_TABLE3 = "simple_table3"; + + public static final String CREATE_TABLE1 = "CREATE TABLE " + TEST_TABLE1 + + " (id INTEGER NOT NULL," + " field1 CHAR(100) DEFAULT NULL," + + " field2 DECIMAL " //+ defaultInt + + " COMMENT 'field2_rem'," + " field3 DECIMAL," + " fkey INTEGER," + + " PRIMARY KEY (id) FOREIGN KEY (fkey) REFERENCES " + + TEST_TABLE3 + "(fk))"; + + public static final String CREATE_TABLE2 = "CREATE TABLE " + TEST_TABLE2 + + " ( " + "finteger integer NOT NULL, " + "ftext text, " + + "fcharacter character (5), " + "fdecimal decimal (5,1), " + + "fnumeric numeric (4,1), " + "fsmallint smallint, " + + "ffloat float, " + "freal real, " + "fdouble double, " + + "fdate date," + " ftime time, PRIMARY KEY (finteger))"; + + public static final String CREATE_TABLE3 = "CREATE TABLE " + TEST_TABLE3 + + " (fk INTEGER NOT NULL," + "" + " PRIMARY KEY (fk))"; + + public static final String CREATE_TABLE4 = "CREATE TABLE " + TEST_TABLE4 + + " (fk INTEGER NOT NULL," + " field1 CHAR(100) NOT NULL," + + " PRIMARY KEY (fk))"; + + public static final String CREATE_TABLE5 = "CREATE TABLE " + TEST_TABLE5 + + "( testId INTEGER NOT NULL, testValue CHAR(200))"; + + public static final String CREATE_TABLE_SALESPEOPLE = "CREATE TABLE " + + SALESPEOPLE_TABLE + " (snum integer, sname character (10)," + + " city character (10), comm real, PRIMARY KEY (snum))"; + + public static final String CREATE_TABLE_CUSTOMERS = "CREATE TABLE " + + CUSTOMERS_TABLE + + " (cnum integer, cname character (10), city character (10)," + + " rating integer, snum integer, PRIMARY KEY (cnum))"; + + public static final String CREATE_TABLE_ORDERS = "CREATE TABLE " + + ORDERS_TABLE + + " (onum integer, amt real, odate date, cnum integer," + + " snum integer, PRIMARY KEY (onum))"; + + public static final String CREATE_TABLE_PARENT = "CREATE TABLE " + + PARENT_TABLE + "(id INTEGER NOT NULL, " + + "name CHAR(200), PRIMARY KEY(id))"; + + public static final String CREATE_TABLE_FKSTRICT = "CREATE TABLE " + + FKSTRICT_TABLE + "(id INTEGER NOT NULL," + "name_id INTEGER," + + "value CHAR(200), PRIMARY KEY(id), " + + "CONSTRAINT fk1 FOREIGN KEY (name_id) " + "REFERENCES " + + PARENT_TABLE + " (id) " + "ON DELETE RESTRICT " + + "ON UPDATE RESTRICT)"; + + public static final String CREATE_TABLE_FKCASCADE = "CREATE TABLE " + + FKCASCADE_TABLE + "(id INTEGER NOT NULL," + "name_id INTEGER," + + "value CHAR(200), PRIMARY KEY(id), " + + "CONSTRAINT fk2 FOREIGN KEY (name_id) " + "REFERENCES " + + PARENT_TABLE + " (id) " + "ON DELETE CASCADE " + + "ON UPDATE CASCADE)"; + + public static final String CREATE_TABLE_SIMPLE1 = "CREATE TABLE " + + SIMPLE_TABLE1 + "(id INTEGER NOT NULL," + "speed INTEGER," + + "size INTEGER)"; + + public static final String CREATE_TABLE_SIMPLE2 = "CREATE TABLE " + + SIMPLE_TABLE2 + "(id INTEGER NOT NULL," + "speed INTEGER," + + "size INTEGER)"; + + public static final String CREATE_TABLE_SIMPLE3 = "CREATE TABLE " + + SIMPLE_TABLE3 + "(id INTEGER NOT NULL," + "speed INTEGER)"; + + public static final String DROP_TABLE1 = "DROP TABLE " + TEST_TABLE1; + + public static final String DROP_TABLE2 = "DROP TABLE " + TEST_TABLE2; + + public static final String DROP_TABLE3 = "DROP TABLE " + TEST_TABLE3; + + public static final String DROP_TABLE4 = "DROP TABLE " + TEST_TABLE4; + + public static final String DROP_TABLE5 = "DROP TABLE " + TEST_TABLE5; + + public static final String DROP_TABLE_CUSTOMERS = "DROP TABLE " + + CUSTOMERS_TABLE; + + public static final String DROP_TABLE_ORDERS = "DROP TABLE " + ORDERS_TABLE; + + public static final String DROP_TABLE_SALESPEOPLE = "DROP TABLE " + + SALESPEOPLE_TABLE; + + public static final String DROP_TABLE_PARENT = "DROP TABLE " + PARENT_TABLE; + + public static final String DROP_TABLE_FKSTRICT = "DROP TABLE " + + FKSTRICT_TABLE; + + public static final String DROP_TABLE_FKCASCADE = "DROP TABLE " + + FKCASCADE_TABLE; + + public static final String DROP_TABLE_SIMPLE1 = "DROP TABLE " + + SIMPLE_TABLE1; + + public static final String DROP_TABLE_SIMPLE2 = "DROP TABLE " + + SIMPLE_TABLE2; + + public static final String DROP_TABLE_SIMPLE3 = "DROP TABLE " + + SIMPLE_TABLE3; + + public static final String INSERT_SALESPEOPLE1 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1001, 'Peel', 'London', .12)"; + + public static final String INSERT_SALESPEOPLE2 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1002, 'Serres', 'SanJose', .13)"; + + public static final String INSERT_SALESPEOPLE3 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1004, 'Motika', 'London', .11)"; + + public static final String INSERT_SALESPEOPLE4 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1007, 'Rifkin', 'Barcelona', .15)"; + + public static final String INSERT_SALESPEOPLE5 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1003, 'Axelrod', 'NewYork', .10)"; + + public static final String INSERT_SALESPEOPLE6 = " INSERT INTO " + + SALESPEOPLE_TABLE + " (snum, sname, city, comm) " + + "VALUES (1013, 'Simpson', 'Kasan', .25)"; + + public static final String INSERT_CUSTOMERS1 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum)" + + " VALUES (2001, 'Hoffman', 'London', 100, 1001)"; + + public static final String INSERT_CUSTOMERS2 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2002, 'Giovanni', 'Rome', 200, 1003)"; + + public static final String INSERT_CUSTOMERS3 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2003, 'Liu', 'SanJose', 200, 1002)"; + + public static final String INSERT_CUSTOMERS4 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2004, 'Grass', 'Berlin', 300, 1002)"; + + public static final String INSERT_CUSTOMERS5 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2006, 'Clemens', 'London', 100, 1001)"; + + public static final String INSERT_CUSTOMERS6 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2008, 'Cisneros', 'SanJose', 300, 1007)"; + + public static final String INSERT_CUSTOMERS7 = " INSERT INTO " + + CUSTOMERS_TABLE + " (cnum, cname, city, rating, snum) " + + "VALUES (2007, 'Pereira', 'Rome', 100, 1004)"; + + public static final String INSERT_ORDERS1 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3001, 18.69, 10/03/1990, 2008, 1007)"; + + public static final String INSERT_ORDERS2 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3003, 767.19, 10/03/1990, 2001, 1001)"; + + public static final String INSERT_ORDERS3 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3002, 1900.10, 10/03/1990, 2007, 1004)"; + + public static final String INSERT_ORDERS4 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3005, 5160.45, 10/03/1990, 2003, 1002)"; + + public static final String INSERT_ORDERS5 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3006, 1098.16, 10/03/1990, 2008, 1007)"; + + public static final String INSERT_ORDERS6 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3009, 1713.23, 10/04/1990, 2002, 1003)"; + + public static final String INSERT_ORDERS7 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3007, 75.75, 10/04/1990, 2004, 1002)"; + + public static final String INSERT_ORDERS8 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3008, 4723.01, 10/05/1990, 2006, 1001)"; + + public static final String INSERT_ORDERS9 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3010, 1309.95, 10/06/1990, 2004, 1002)"; + + public static final String INSERT_ORDERS10 = " INSERT INTO " + ORDERS_TABLE + + " (onum, amt, odate, cnum, snum) " + + "VALUES (3011, 9891.88, 10/06/1990, 2006, 1001)"; + + public static void fillParentTable(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement + .execute("INSERT INTO " + PARENT_TABLE + " VALUES(1, 'test1')"); + statement.execute("INSERT INTO " + PARENT_TABLE + " VALUES(2,'test2')"); + statement + .execute("INSERT INTO " + PARENT_TABLE + " VALUES(3, 'test3')"); + } + + public static void fillFKStrictTable(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement.execute("INSERT INTO " + FKSTRICT_TABLE + + " VALUES(1, 1, '1')"); + statement.execute("INSERT INTO " + FKSTRICT_TABLE + + " VALUES(2, 2, '2')"); + statement.execute("INSERT INTO " + FKSTRICT_TABLE + + " VALUES(3, 1, '3')"); + } + + public static void fillFKCascadeTable(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement.execute("INSERT INTO " + FKCASCADE_TABLE + + " VALUES(1, 1, '1')"); + statement.execute("INSERT INTO " + FKCASCADE_TABLE + + " VALUES(2, 2, '2')"); + statement.execute("INSERT INTO " + FKCASCADE_TABLE + + " VALUES(3, 1, '3')"); + } + + public static void fillSimpleTable1(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement + .execute("INSERT INTO " + SIMPLE_TABLE1 + " VALUES(1, 10, 20)"); + statement.execute("INSERT INTO " + SIMPLE_TABLE1 + " VALUES(2, 5, 7)"); + } + + public static void fillSimpleTable3(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement.execute("INSERT INTO " + SIMPLE_TABLE3 + " VALUES(1, 8)"); + statement.execute("INSERT INTO " + SIMPLE_TABLE3 + " VALUES(2, 6)"); + statement.execute("INSERT INTO " + SIMPLE_TABLE3 + " VALUES(3, 4)"); + } + + public static void fillSalesPeopleTable(Connection conn) + throws SQLException { + Statement statement = conn.createStatement(); + + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE1); + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE2); + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE3); + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE4); + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE5); + statement.execute(DatabaseCreator.INSERT_SALESPEOPLE6); + } + + public static void fillCustomersTable(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + + statement.execute(DatabaseCreator.INSERT_CUSTOMERS1); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS2); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS3); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS4); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS5); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS6); + statement.execute(DatabaseCreator.INSERT_CUSTOMERS7); + } + + public static void fillOrdersTable(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + + statement.execute(DatabaseCreator.INSERT_ORDERS1); + statement.execute(DatabaseCreator.INSERT_ORDERS2); + statement.execute(DatabaseCreator.INSERT_ORDERS3); + statement.execute(DatabaseCreator.INSERT_ORDERS4); + statement.execute(DatabaseCreator.INSERT_ORDERS5); + statement.execute(DatabaseCreator.INSERT_ORDERS6); + statement.execute(DatabaseCreator.INSERT_ORDERS7); + statement.execute(DatabaseCreator.INSERT_ORDERS8); + statement.execute(DatabaseCreator.INSERT_ORDERS9); + statement.execute(DatabaseCreator.INSERT_ORDERS10); + } + + public static void fillTestTable1(Connection conn, int numberOfRecords) + throws SQLException { + Statement statement = conn.createStatement(); + for (int id = 0; id < numberOfRecords; id++) { + String value = DatabaseCreator.defaultString + id; + String insertQuery = "INSERT INTO " + DatabaseCreator.TEST_TABLE1 + + " (id, field1, field2, field3) VALUES(" + id + ", '" + + value + "', " + id + ", " + id + ")"; + statement.execute(insertQuery); + } + } + + public static void fillTestTable2(Connection conn, int startID, int endID, + long time) throws SQLException { + Statement statement = conn.createStatement(); + for (int id = startID; id <= endID; id++) { + double value = id + DatabaseCreator.defaultDouble; + String insertQuery = "INSERT INTO " + DatabaseCreator.TEST_TABLE2 + + " (finteger, ftext, fcharacter, fdecimal, fnumeric," + + " fsmallint, ffloat, freal, fdouble, fdate, ftime)" + + " VALUES (" + id + ", '" + DatabaseCreator.defaultString + + id + "'," + " '" + DatabaseCreator.defaultCharacter + id + + "', " + value + ", " + value + "," + value + ", " + value + + ", " + value + "," + value + ", '" + + new Date(time).toString() + "'," + " '" + + new Time(time).toString() + "')"; + statement.execute(insertQuery); + } + } + + public static void fillTestTable2(Connection conn, int numberOfRecords) + throws SQLException { + Statement statement = conn.createStatement(); + for (int id = 0; id < numberOfRecords; id++) { + double value = id + DatabaseCreator.defaultDouble; + String insertQuery = "INSERT INTO " + DatabaseCreator.TEST_TABLE2 + + " (finteger, ftext, fcharacter, fdecimal, fnumeric," + + " fsmallint, ffloat, freal, fdouble)" + " VALUES (" + id + + ", '" + DatabaseCreator.defaultString + id + "'," + " '" + + DatabaseCreator.defaultCharacter + id + "', " + value + + ", " + value + "," + value + ", " + value + ", " + value + + "," + value + ")"; + statement.execute(insertQuery); + } + } + + public static void fillTestTable4(Connection conn, int numberOfRecords) + throws SQLException { + Statement statement = conn.createStatement(); + for (int id = 0; id < numberOfRecords; id++) { + String insertQuery = "INSERT INTO " + DatabaseCreator.TEST_TABLE4 + + " (fk, field1) VALUES(" + id + ", \"" + + DatabaseCreator.defaultString + id + "\")"; + statement.execute(insertQuery); + } + } + + public static void fillTestTable5(Connection conn) throws SQLException { + Statement statement = conn.createStatement(); + statement.execute("INSERT INTO " + TEST_TABLE5 + " VALUES(1, '0')"); + statement.execute("INSERT INTO " + TEST_TABLE5 + " VALUES(2, '3')"); + statement.execute("INSERT INTO " + TEST_TABLE5 + " VALUES(3, '4')"); + } +} diff --git a/sql/src/test/java/tests/support/Support_SQL.java b/sql/src/test/java/tests/support/Support_SQL.java new file mode 100644 index 0000000..7c42163 --- /dev/null +++ b/sql/src/test/java/tests/support/Support_SQL.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.support; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class Support_SQL { + + public static String sqlDriver = null; + + public static String sqlLogin = null; + + public static String sqlCatalog = null; + + public static String sqlHost = null; + + public static String sqlUrl = null; + + public static String sqlPassword = null; + + public static String sqlUser = null; + + public static int sqlMaxConnections = 1; + + public static int sqlMaxTasks = 0; + + public static void loadDriver() { + try { + loadProperties(Class.forName("tests.support.Support_SQL") + .getResourceAsStream("/connection.properties")); + Class.forName(sqlDriver).newInstance(); + } catch (Exception ex) { + System.err.println("Unexpected exception " + ex.toString()); + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(Support_SQL.sqlUrl, + Support_SQL.sqlLogin, Support_SQL.sqlPassword); + } + + public static Connection getConnection(String url, String login, + String password) throws SQLException { + + return DriverManager.getConnection(url, login, password); + } + + public static boolean isEqual(byte[] b1, int off1, byte[] b2, int off2, + int len) { + for (int i = 0; i < len; ++i) + if (b1[i + off1] != b2[i + off2]) + return false; + return true; + } + + private static void loadProperties(InputStream fileName) throws IOException { + Properties properties = new Properties(); + properties.load(fileName); + sqlDriver = properties.getProperty("sqlDriver"); + sqlLogin = properties.getProperty("sqlLogin"); + sqlCatalog = properties.getProperty("sqlCatalog"); + sqlHost = properties.getProperty("sqlHost"); + sqlUrl = properties.getProperty("sqlUrlPrefix") + sqlHost + "/" + + sqlCatalog; + sqlPassword = properties.getProperty("sqlPassword"); + sqlUser = properties.getProperty("sqlUser"); + sqlMaxConnections = Integer.parseInt(properties + .getProperty("sqlMaxConnections")); + sqlMaxTasks = Integer.parseInt(properties.getProperty("sqlMaxTasks")); + } +} diff --git a/sql/src/test/java/tests/support/ThreadPool.java b/sql/src/test/java/tests/support/ThreadPool.java new file mode 100644 index 0000000..84f22a9 --- /dev/null +++ b/sql/src/test/java/tests/support/ThreadPool.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tests.support; + +import java.util.LinkedList; + +public class ThreadPool extends ThreadGroup { + + private boolean isAlive; + + private LinkedList<Runnable> taskQueue; + + private int threadID; + + private static int threadPoolID; + + public ThreadPool(int numThreads) { + super("ThreadPool-" + (threadPoolID++)); + setDaemon(true); + + isAlive = true; + + taskQueue = new LinkedList<Runnable>(); + for (int i = 0; i < numThreads; i++) { + new PooledThread().start(); + } + } + + public synchronized void runTask(Runnable task) { + if (!isAlive) { + throw new IllegalStateException(); + } + if (task != null) { + taskQueue.add(task); + notify(); + } + } + + protected synchronized Runnable getTask() throws InterruptedException { + while (taskQueue.size() == 0) { + if (!isAlive) { + return null; + } + wait(); + } + return (Runnable) taskQueue.removeFirst(); + } + + public synchronized void close() { + if (isAlive) { + isAlive = false; + taskQueue.clear(); + interrupt(); + } + } + + public void join() { + synchronized (this) { + isAlive = false; + notifyAll(); + } + + Thread[] threads = new Thread[activeCount()]; + int count = enumerate(threads); + for (int i = 0; i < count; i++) { + try { + threads[i].join(); + } catch (InterruptedException ex) { + System.err.println(ex.getMessage()); + } + } + } + + private class PooledThread extends Thread { + + public PooledThread() { + super(ThreadPool.this, "PooledThread-" + (threadID++)); + } + + public void run() { + while (!isInterrupted()) { + + Runnable task = null; + try { + task = getTask(); + } catch (InterruptedException ex) { + System.err.println(ex.getMessage()); + } + + if (task == null) { + return; + } + + try { + task.run(); + } catch (Throwable t) { + System.err.println(t.getMessage()); + } + } + } + } +} diff --git a/sql/src/test/resources/connection.properties b/sql/src/test/resources/connection.properties new file mode 100644 index 0000000..2e49346 --- /dev/null +++ b/sql/src/test/resources/connection.properties @@ -0,0 +1,9 @@ +sqlDriver = SQLite.JDBCDriver +sqlLogin = +sqlCatalog =sqliteTest.db +sqlHost = +sqlUrlPrefix = jdbc:sqlite: +sqlPassword = +sqlUser = +sqlMaxConnections = 30 +sqlMaxTasks = 10000 diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.golden.ser Binary files differnew file mode 100644 index 0000000..d20eed1 --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/BatchUpdateExceptionTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.golden.ser Binary files differnew file mode 100644 index 0000000..9ecd6e1 --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/DataTruncationTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.golden.ser Binary files differnew file mode 100644 index 0000000..6e58660 --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLExceptionTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.golden.ser Binary files differnew file mode 100644 index 0000000..be37cb8 --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/SQLWarningTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/TimestampTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/TimestampTest.golden.ser Binary files differnew file mode 100644 index 0000000..4e51a0a --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/java/sql/TimestampTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.golden.ser Binary files differnew file mode 100644 index 0000000..642e2fc --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/ConnectionEventTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/RowSetMetaDataImplTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/RowSetMetaDataImplTest.golden.ser Binary files differnew file mode 100644 index 0000000..edd8bee --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/RowSetMetaDataImplTest.golden.ser diff --git a/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/serial/SerialExceptionTest.golden.ser b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/serial/SerialExceptionTest.golden.ser Binary files differnew file mode 100644 index 0000000..71ed471 --- /dev/null +++ b/sql/src/test/resources/serialization/org/apache/harmony/sql/tests/javax/sql/rowset/serial/SerialExceptionTest.golden.ser |