| /* |
| * Copyright (C) 2008 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 libcore.sqlite; |
| |
| import SQLite.Authorizer; |
| import SQLite.Blob; |
| import SQLite.BusyHandler; |
| import SQLite.Callback; |
| import SQLite.Constants; |
| import SQLite.Database; |
| import SQLite.Exception; |
| import SQLite.Function; |
| import SQLite.FunctionContext; |
| import SQLite.ProgressHandler; |
| import SQLite.Stmt; |
| import SQLite.TableResult; |
| import SQLite.Trace; |
| import SQLite.Vm; |
| import java.io.File; |
| import java.io.InputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URL; |
| import java.sql.DatabaseMetaData; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.logging.Logger; |
| import tests.support.DatabaseCreator; |
| import tests.support.MockFunction; |
| import tests.support.ThreadPool; |
| |
| public final class OldDatabaseTest extends OldSQLiteTest { |
| |
| private static ErrorTracker tracker = null; |
| |
| private Statement statement; |
| |
| private Database db = null; |
| |
| private static final int numThreads = 10; |
| |
| private static final int numOfRecords = 30; |
| |
| @Override public void setUp() throws java.lang.Exception { |
| super.setUp(); |
| assertNotNull("Could not establish DB connection",conn); |
| tracker = new ErrorTracker(); |
| |
| statement = conn.createStatement(); |
| |
| // Cleanup tables if necessary |
| |
| DatabaseMetaData meta = conn.getMetaData(); |
| assertNotNull(meta); |
| ResultSet userTab = meta.getTables(null, null, null, null); |
| while (userTab.next()) { |
| String tableName = userTab.getString("TABLE_NAME"); |
| this.statement.execute("drop table " + tableName); |
| } |
| |
| // Create default test table |
| statement.execute(DatabaseCreator.CREATE_TABLE_SIMPLE1); |
| statement.close(); |
| |
| db = new Database(); |
| db.open(dbFile.getPath(), 0); |
| db.busy_handler(null); |
| } |
| |
| public void tearDown() throws java.lang.Exception { |
| try { |
| db.close(); |
| } catch (Exception e) { |
| if (!(e.getMessage().equals("database already closed"))) { |
| System.err.println("Error closing DB " + dbFile.getPath()); |
| } |
| } |
| tracker.reset(); |
| super.tearDown(); |
| } |
| |
| public void testDatabase() throws Exception { |
| // db closed |
| Database db2 = new Database(); |
| db.close(); |
| db2 = new Database(); |
| db2.open(dbFile.getPath(), 0); |
| db2.close(); |
| db.open(dbFile.getPath(), 0); |
| //db is open |
| db2.open(dbFile.getPath(), 0); |
| db2.close(); |
| } |
| |
| public void testOpen() throws Exception { |
| db.close(); |
| db.open(dbFile.getPath(), 0); |
| // open second db while db1 still open |
| Database db2 = new Database(); |
| db2.open(dbFile.getPath(), 0); |
| db2.open(dbFile.getPath(), 0); |
| db2.close(); |
| // open non db file |
| try { |
| URL file = OldDatabaseTest.class.getResource("/blob.c"); |
| db2.open(file.getPath(), 0); |
| fail("Should not be able to open non db file"); |
| } catch (SQLite.Exception e) { |
| assertEquals("unknown error in open", e.getMessage()); |
| } |
| } |
| |
| public void testOpen_aux_file() { |
| File temp = null; |
| try { |
| db.open_aux_file(""); |
| fail("open should fail"); |
| } catch (Exception e) { |
| assertEquals("unsupported", e.getMessage()); |
| } |
| |
| /* |
| try { |
| temp = File.createTempFile("openAuxMethod", ".db"); |
| db.open_aux_file(""); |
| db.exec("create table AUX_TABLE", null); |
| db.close(); |
| } catch (Exception e) { |
| temp.delete(); |
| fail("Error handling temporary file "+e.getMessage()); |
| e.printStackTrace(); |
| } catch (IOException e) { |
| temp.delete(); |
| fail("Could not create temporary File"); |
| e.printStackTrace(); |
| } |
| try { |
| db.open(dbFile.getPath(),0); |
| db.exec("select * from AUX_TABLE", null); |
| fail("Statement should fail"); |
| } catch (Exception e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| |
| temp.delete(); |
| */ |
| } |
| |
| public void testClose() throws Exception { |
| try { |
| db.close(); |
| db.get_table("test"); |
| fail(); |
| } catch (Exception e) { |
| assertTrue(e.getMessage().equals("database already closed")); |
| try { |
| db.open(dbFile.getPath(), 0); |
| } catch (Exception e1) { |
| fail("Database object could not be reopened after 'close': " |
| + e.getMessage()); |
| e1.printStackTrace(); |
| } |
| } |
| |
| try { |
| db.close(); |
| db.close(); |
| fail(); |
| } catch (Exception e) { |
| assertTrue(e.getMessage().equals("database already closed")); |
| db.open(dbFile.getPath(), 0); |
| } |
| } |
| |
| public void testExecStringCallback() throws Exception { |
| TableResult res = new TableResult(); |
| db.exec("insert into " + DatabaseCreator.SIMPLE_TABLE1 |
| + " VALUES(1, 10, 20)", null); |
| db.exec("select * from " + DatabaseCreator.SIMPLE_TABLE1, res); |
| db.exec("delete from " + DatabaseCreator.SIMPLE_TABLE1 + " where 1", null); |
| String row[] = (String[]) res.rows.elementAt(0); |
| assertEquals(Integer.parseInt(row[0]), 1); |
| assertEquals(Integer.parseInt(row[1]), 10); |
| assertEquals(Integer.parseInt(row[2]), 20); |
| } |
| |
| public void testExecStringCallbackStringArray() throws Exception { |
| TableResult res = new TableResult(); |
| String args[] = new String[1]; |
| args[0] = "table"; |
| db.exec("select name from sqlite_master where type = '%q';", res, args); |
| String[] s = (String[]) res.rows.elementAt(0); |
| assertEquals(s[0], DatabaseCreator.SIMPLE_TABLE1); |
| |
| try { |
| db.exec("select name from sqlite_master where type = ", res, args); |
| fail("Testmethod should fail"); |
| } catch (Exception e) { |
| // Ok |
| } |
| } |
| |
| public void testLast_insert_rowid() throws Exception { |
| assertEquals(0, db.last_insert_rowid()); |
| db.exec("create table TEST5(id integer, firstname text, lastname text);", null); |
| db.exec("insert into TEST5 values (1,'James','Bond');", null); |
| db.exec("insert into TEST5 values (2,'Fiona','Apple');", null); |
| assertEquals(2, db.last_insert_rowid()); |
| assertEquals(db.last_insert_rowid(), db.last_insert_rowid()); |
| |
| db.exec("drop table TEST5;", null); |
| assertEquals(2, db.last_insert_rowid()); |
| } |
| |
| /** |
| * Reason for failure unknown: Database should be locked. Specification |
| * of interrupt is scarce. |
| */ |
| public void testInterrupt() throws Exception, SQLException { |
| ThreadPool threadPool = new ThreadPool(numThreads); |
| |
| // initialization |
| ResultSet userTabs; |
| userTabs = conn.getMetaData().getTables(null, null, null, null); |
| while (userTabs.next()) { |
| String tableName = userTabs.getString("TABLE_NAME"); |
| if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { |
| statement.execute(DatabaseCreator.DROP_TABLE1); |
| } |
| } |
| db.exec(DatabaseCreator.CREATE_TABLE3, null); |
| db.exec(DatabaseCreator.CREATE_TABLE1, null); |
| |
| int id1 = numOfRecords - 3; |
| threadPool.runTask(createTask1(id1, dbFile.getPath(), tracker)); |
| // should not be able to do any other insertions since task 1 holds lock |
| int id2 = numOfRecords + 3; |
| threadPool |
| .runTask(createTask2Interrupt(id2, dbFile.getPath(), tracker)); |
| |
| threadPool.join(); |
| |
| List<String> errors = tracker.getErrors(); |
| System.out.println("Last error: " + db.error_message()); |
| if (errors.size() > 0) { |
| assertEquals(errors.get(0), db.error_string(Constants.SQLITE_LOCKED)); |
| for (String s : errors) { |
| Logger.global.info("INTERRUPT Error: " + s); |
| } |
| |
| } else { |
| fail("Should have one exception: database should be locked."); |
| } |
| |
| // reset |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE1 + " where 1", null); |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE3 + " where 1", null); |
| } |
| |
| /** |
| * Returns wrong number for updates: returns value > 1 for select. |
| */ |
| public void testChanges() throws Exception { |
| TableResult res = new TableResult(); |
| assertTrue(db.changes() == 0); |
| db.exec("INSERT INTO " + DatabaseCreator.SIMPLE_TABLE1 |
| + " VALUES(2, 5, 7);", null); |
| int rows = (int) db.changes(); |
| assertEquals(1,db.changes()); |
| db.exec("update " + DatabaseCreator.SIMPLE_TABLE1 |
| + " set speed = 7, size= 5 where id = 2;", null); |
| assertEquals(1,db.changes()); |
| db.exec("select * from " + DatabaseCreator.SIMPLE_TABLE1, res); |
| assertEquals(0,db.changes()); |
| db.exec("INSERT INTO " + DatabaseCreator.SIMPLE_TABLE1 |
| + " VALUES(8, 5, 7);", null); |
| db.exec("Update "+DatabaseCreator.SIMPLE_TABLE1+" set speed = 10;",null); |
| assertTrue(db.changes() > 2); |
| } |
| |
| /** |
| * method test fails once in a while. Cannot be sure that exception is |
| * thrown in every test execution. |
| */ |
| public void testBusy_handler() throws SQLException, Exception { |
| TestBusyHandler bh = new TestBusyHandler(); |
| db.busy_handler(bh); |
| int counter = 0; |
| ThreadPool threadPool = new ThreadPool(numThreads); |
| |
| // initialization |
| ResultSet userTabs; |
| userTabs = conn.getMetaData().getTables(null, null, null, null); |
| while (userTabs.next()) { |
| String tableName = userTabs.getString("TABLE_NAME"); |
| if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { |
| statement.execute(DatabaseCreator.DROP_TABLE1); |
| } |
| } |
| db.exec(DatabaseCreator.CREATE_TABLE3, null); |
| db.exec(DatabaseCreator.CREATE_TABLE1, null); |
| |
| |
| try { |
| conn.setAutoCommit(false); |
| int id1 = numOfRecords - 3; |
| threadPool.runTask(createTask1(id1, dbFile.getPath(), tracker)); |
| int id2 = numOfRecords + 3; |
| threadPool.runTask(createTask2(id2, dbFile.getPath(), tracker)); |
| int oldID = 5; |
| int newID = 100; |
| threadPool.runTask(createTask3(oldID, dbFile.getPath(), newID, |
| tracker)); |
| |
| threadPool.join(); |
| |
| List<String> errors = tracker.getErrors(); |
| if (errors.size() > 0) { |
| // assertEquals(errors.get(0), |
| // db.error_string(Constants.SQLITE_LOCKED)); |
| for (String s: errors) { |
| System.out.println("Round 2 Error: "+s); |
| } |
| } else { |
| fail("No error happened"); |
| } |
| |
| // reset |
| |
| |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE1 + " where 1", |
| null); |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE3 + " where 1", |
| null); |
| // |
| // // increase timeout for retry |
| // db.busy_timeout(1000); |
| // db.busy_handler(bh); |
| // tracker.reset(); |
| |
| // threadPool = new ThreadPool(numThreads); |
| // |
| // threadPool.runTask(createTask1(id1, dbFile.getPath(), tracker)); |
| // threadPool.runTask(createTask2(id2, dbFile.getPath(), tracker)); |
| // |
| // threadPool.join(); |
| // |
| // errors = tracker.getErrors(); |
| // if (errors.size() > 0) { |
| // // assertEquals(errors.get(0), |
| // // db.error_string(Constants.SQLITE_LOCKED)); |
| // for (String s: errors) { |
| // System.out.println("Round 2 Error"+s); |
| // } |
| // } else { |
| // // ok |
| // System.out.println("BUSY: No Error!"); |
| // } |
| // |
| // |
| } finally { |
| conn.setAutoCommit(true); |
| db.exec(DatabaseCreator.DROP_TABLE1, null); |
| db.exec(DatabaseCreator.DROP_TABLE3, null); |
| } |
| } |
| |
| /** |
| * test fails. Cannot be sure that exception is thrown every time. |
| * Database does not lock values. |
| */ |
| public void testBusy_timeout() throws Exception, SQLException { |
| int counter = 0; |
| ThreadPool threadPool = new ThreadPool(numThreads); |
| |
| // initialization |
| ResultSet userTabs = conn.getMetaData().getTables(null, null, null, null); |
| while (userTabs.next()) { |
| String tableName = userTabs.getString("TABLE_NAME"); |
| if (tableName.equals(DatabaseCreator.TEST_TABLE1)) { |
| statement.execute(DatabaseCreator.DROP_TABLE1); |
| } |
| } |
| db.exec(DatabaseCreator.CREATE_TABLE3, null); |
| db.exec(DatabaseCreator.CREATE_TABLE1, null); |
| |
| // test run |
| try { |
| conn.setAutoCommit(false); |
| |
| // DatabaseCreator.fillTestTable1(conn, numOfRecords); |
| // set to fail immediately if table is locked. |
| db.busy_handler(null); |
| db.busy_timeout(0); |
| int id1 = numOfRecords - 3; |
| |
| threadPool.runTask(createTask2(id1, dbFile.getPath(), tracker)); |
| int id2 = numOfRecords + 3; |
| threadPool.runTask(createTask1(id2, dbFile.getPath(), tracker)); |
| int oldID = 5; |
| int newID = 100; |
| threadPool.runTask(createTask3(oldID, dbFile.getPath(), newID, |
| tracker)); |
| |
| threadPool.join(); |
| |
| List<String> errors = tracker.getErrors(); |
| assertTrue("No error occurred on DB but should have",errors.size() > 0); |
| |
| assertEquals(errors.get(0), |
| db.error_string(Constants.SQLITE_LOCKED)); |
| assertEquals(errors.get(0), "database is locked"); |
| |
| // reset |
| |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE1 + " where 1", |
| null); |
| db.exec("delete from " + DatabaseCreator.TEST_TABLE3 + " where 1", |
| null); |
| |
| // increase timeout for retry |
| db.busy_timeout(10000); |
| db.busy_handler(null); |
| tracker.reset(); |
| threadPool = new ThreadPool(numThreads); |
| |
| threadPool.runTask(createTask1(id1, dbFile.getPath(), tracker)); |
| threadPool.runTask(createTask2(id2, dbFile.getPath(), tracker)); |
| |
| threadPool.join(); |
| |
| errors = tracker.getErrors(); |
| if (errors.size() > 0) { |
| fail("busy timeout should prevent from lock exception!"); |
| for (String s: errors) { |
| System.out.println("Round 2 Error"+s); |
| } |
| } else { |
| // ok |
| } |
| } finally { |
| conn.setAutoCommit(true); |
| // cleanup |
| db.exec(DatabaseCreator.DROP_TABLE1, null); |
| db.exec(DatabaseCreator.DROP_TABLE3, null); |
| } |
| } |
| |
| public void testGet_tableString() throws Exception { |
| TableResult emptyTable = new TableResult(); |
| //select from empty table |
| TableResult res = db.get_table("select * from " + DatabaseCreator.SIMPLE_TABLE1); |
| assertEquals(res.toString(), emptyTable.toString()); |
| //fill table-> t |
| // DatabaseCreator.fillSimpleTable1(conn); |
| // res = db.get_table("select * from " |
| // + DatabaseCreator.SIMPLE_TABLE1); |
| // assertFalse(emptyTable.toString().equals(res.toString())); |
| |
| db.exec("insert into " + DatabaseCreator.SIMPLE_TABLE1 + " VALUES(1, 10, 20)", null); |
| res = db.get_table("select * from " + DatabaseCreator.SIMPLE_TABLE1); |
| db.exec("delete from " + DatabaseCreator.SIMPLE_TABLE1 |
| + " where 1", null); |
| String row[] = (String[]) res.rows.elementAt(0); |
| assertEquals(Integer.parseInt(row[0]), 1); |
| assertEquals(Integer.parseInt(row[1]), 10); |
| assertEquals(Integer.parseInt(row[2]), 20); |
| } |
| |
| public void testGet_tableStringStringArray() throws Exception { |
| String args[] = new String[1]; |
| args[0] = "table"; |
| String argsFail[] = new String[1]; |
| try { |
| db.get_table("select name from sqlite_master where type = ", argsFail); |
| fail("Testmethod should fail"); |
| } catch (Exception e) { |
| } |
| |
| TableResult res = db.get_table( |
| "select name from sqlite_master where type = '%q'", |
| args); |
| String[] s = (String[]) res.rows.elementAt(0); |
| assertEquals(s[0], DatabaseCreator.SIMPLE_TABLE1); |
| } |
| |
| public void testGet_tableStringStringArrayTableResult() throws Exception { |
| String args[] = new String[1]; |
| String argsFail[] = new String[1]; |
| TableResult res = new TableResult(); |
| TableResult defaultTableRes = new TableResult(); |
| args[0] = "table"; |
| |
| try { |
| db.get_table("select name from sqlite_master where type = '%q'", argsFail, res); |
| assertEquals(defaultTableRes.toString(), res.toString()); |
| } catch (Exception e) { |
| db.get_table("select name from sqlite_master where type = '%q'", args, res); |
| String[] s = (String[]) res.rows.elementAt(0); |
| assertEquals(s[0], DatabaseCreator.SIMPLE_TABLE1); |
| System.out.println("DatabaseTest.testGet_tableStringStringArrayTableResult() " |
| + Arrays.toString(res.types)); |
| } |
| } |
| |
| public void testComplete() { |
| assertFalse(db.complete("create")); |
| assertTrue(db.complete("create table TEST (res double);")); |
| } |
| |
| public void testVersion() { |
| String version = db.version(); |
| if (version != null) { |
| assertTrue(Integer.parseInt(db.version().substring(0, 1)) > 0); |
| assertEquals(db.version(), db.version()); |
| } else { |
| fail("DB version info missing"); |
| } |
| } |
| |
| public void testDbversion() throws Exception { |
| String verNo = ""; |
| try { |
| verNo = db.dbversion(); |
| db.close(); |
| assertEquals(db.dbversion(),"unknown"); |
| db.open(dbFile.getPath(), 0); |
| assertEquals(verNo, db.dbversion()); |
| } catch (Exception e) { |
| db.open(dbFile.getPath(), 0); |
| } |
| |
| assertTrue(Integer.parseInt(verNo.substring(0, 1))>= 3 ); |
| |
| } |
| |
| public void testCreate_function() throws Exception { |
| double input = 1.0; |
| db.exec("create table TEST (res double)", null); |
| db.exec("insert into TEST values (" + Double.toString(input) + ")", |
| null); |
| TableResult res = new TableResult(); |
| Function sinFunc = (Function) new SinFunc(); |
| db.create_function("sin", 1, sinFunc); |
| db.exec("select sin(res) from TEST WHERE res = " |
| + Double.toString(input), res); |
| String row[] = (String[]) res.rows.elementAt(0); |
| String val = row[0]; |
| double sinusVal = Double.parseDouble(val); |
| double funcVal = Math.sin(input); |
| |
| assertTrue(Math.round(funcVal) == Math.round(sinusVal)); |
| } |
| |
| /** |
| * Aggregation function not called. |
| */ |
| public void testCreate_aggregate() throws Exception { |
| TestTrace t = new TestTrace(); |
| MockFunction aggFunction = new MockFunction(); |
| db.exec("create table TEST(id integer, firstname text, lastname text)", null); |
| db.exec("insert into TEST values(3, 'James', 'Bond'); ", null); |
| db.exec("insert into TEST values(4, 'Fiona', 'Apple'); ", null); |
| db.trace((Trace) t); |
| db.create_aggregate("myaggfunc", 1, aggFunction); |
| db.function_type("myaggfunc", Constants.SQLITE3_TEXT); |
| db.exec("PRAGMA show_datatypes = on", null); |
| |
| assertFalse(aggFunction.functionCalled); |
| assertFalse(aggFunction.stepCalled); |
| assertFalse(aggFunction.lastStepCalled); |
| db.exec("select myaggfunc(TEST.firstname) from TEST", t); |
| assertTrue(aggFunction.stepCalled); |
| assertTrue(aggFunction.lastStepCalled); |
| assertTrue(aggFunction.functionCalled); |
| |
| assertEquals("James Fiona ",aggFunction.getAggValue()); |
| db.exec("drop table TEST", null); |
| |
| try { |
| db.create_aggregate("myaggfunc", 0, null); |
| } catch (Throwable e) { |
| assertEquals("null SQLite.Function not allowed",e.getMessage()); |
| } |
| |
| try { |
| db.create_aggregate("myaggfunc", 0, aggFunction); |
| } catch (Throwable e) { |
| assertEquals("wrong number of arguments to function myaggfunc()",e.getMessage()); |
| } |
| } |
| |
| public void testFunction_type() throws Exception { |
| double input = 1.0; |
| TableResult res = new TableResult(); |
| Function sinFunc = (Function) new SinFunc(); |
| |
| db.exec("PRAGMA show_datatypes = on", null); |
| db.exec("create table TEST (res double)", null); |
| db.exec("insert into TEST values (" + Double.toString(input) + ")", |
| null); |
| |
| db.create_function("sin", 1, sinFunc); |
| db.function_type("sin", Constants.SQLITE_FLOAT); |
| res = db.get_table("select sin(res) from TEST WHERE res = " |
| + Double.toString(input)); |
| |
| String row[] = (String[]) res.rows.elementAt(0); |
| String val = row[0]; |
| assertTrue("double".equalsIgnoreCase(res.types[0])); |
| assertSame(Math.round(Math.sin(input)), Math.round(Double.parseDouble(val))); |
| |
| // function determines return type: test that Double type is returned. |
| db.function_type("sin", Constants.SQLITE_BLOB); |
| Stmt s = db.prepare("select sin(res) from TEST WHERE res = ?"); |
| s.bind(1, input); |
| s.step(); |
| |
| res = db.get_table("select sin(res) from TEST WHERE res = " |
| + Double.toString(input)); |
| assertTrue("double".equalsIgnoreCase(res.types[0])); |
| row = (String[]) res.rows.elementAt(0); |
| val = row[0]; |
| assertSame(Math.round(Math.sin(input)), Math.round(Double.parseDouble(val))); |
| } |
| |
| public void testLast_error() { |
| assertEquals(db.last_error(), Constants.SQLITE_OK); |
| try { |
| db.exec("create table TEST (res double)",null); |
| db.exec("create table TEST (res double)",null); |
| fail("Error should have happened"); |
| } catch (Exception e) { |
| assertEquals(db.last_error(),db.last_error()); |
| assertEquals(db.last_error(),Constants.SQLITE_ERROR); |
| } |
| } |
| |
| public void testSet_last_error() { |
| assertEquals(db.last_error(), Constants.SQLITE_OK); |
| try { |
| db.exec("sel from test;", null); |
| } catch (Exception e) { |
| assertEquals(Constants.SQLITE_ERROR,db.last_error()); |
| } |
| } |
| |
| public void testError_message() { |
| String statement = "create table TEST (res double)"; |
| try { |
| db.exec(statement,null); |
| db.exec(statement,null); |
| fail("DB Error expected"); |
| } catch (Exception e) { |
| String dbError = db.error_message(); |
| assertTrue(e.getMessage().equals(dbError)); |
| |
| } |
| } |
| |
| public void testError_string() { |
| TestTrace t = new TestTrace(); |
| assertEquals(db.last_error(), Constants.SQLITE_OK); |
| String errorString = db.error_string(Constants.SQLITE_ERROR); |
| try { |
| db.trace((Trace) t); |
| db.exec("create table TEST (res double)", t); |
| db.exec("create table TEST (res double)", t); |
| } catch (Exception e) { |
| assertEquals(db.last_error(), Constants.SQLITE_ERROR); |
| if (db.is3()) { |
| assertEquals("Unsupported Method (sqlite 3): error_string", db |
| .error_string(db.last_error()), errorString); |
| } |
| } |
| } |
| |
| /** |
| * ASCII encoding does not work: a UTF encoded val is returned. Spec is not |
| * sufficient. Might be that test impl is wrong or String constructor for |
| * the ASCII encoding. |
| */ |
| public void testSet_encoding() throws UnsupportedEncodingException, Exception { |
| String input = "\u00bfMa\u00f1ana\u003f"; // ?Manana? |
| TableResult res = new TableResult(); |
| String refOutput = null; |
| Stmt stat = null; |
| |
| // DB setup |
| db.exec("create table encodingTest (encoded text DEFAULT NULL);", |
| null); |
| stat = db |
| .prepare("insert into encodingTest(encoded) values(:one);"); |
| stat.bind(1, input); |
| stat.step(); |
| // stat.close(); |
| db.exec("select * from encodingTest;", res); |
| String[] encInput = (String[]) res.rows.elementAt(0); |
| String output = encInput[0]; |
| assertEquals(input, output); |
| // db.exec("delete from encodingTest where 1", null); |
| |
| // tests for different encoding schemes |
| String[] charsetNames = {"UTF-8", "UTF-16", "UTF-16BE", "UTF-16LE"}; |
| for (int i = 0; i < charsetNames.length; i++) { |
| byte[] encInputBytes = input.getBytes(charsetNames[i]); |
| db.set_encoding(charsetNames[i]); |
| db.exec("select * from encodingTest;", res); |
| String[] encOutput = (String[]) res.rows.elementAt(0); |
| String inputAsString = new String(encInputBytes,charsetNames[i]); |
| assertEquals(inputAsString, encOutput[0]); |
| } |
| |
| // Default tests |
| db.set_encoding("UTF-16"); |
| db.exec("select * from encodingTest;", res); |
| String[] encOutput1 = (String[]) res.rows.elementAt(0); |
| assertEquals("Got "+encOutput1[0]+" as UTF-16",input,encOutput1[0]); |
| |
| db.set_encoding("US-ASCII"); |
| db.exec("select * from encodingTest;", res); |
| String[] encOutput2 = (String[]) res.rows.elementAt(0); |
| assertEquals(new String(input.getBytes(),"US-ASCII"),encOutput2[0]); |
| |
| // DB teardown |
| stat.close(); |
| db.exec("delete from encodingTest", null); |
| |
| // Default tests |
| try { |
| db.set_encoding(""); |
| fail("invalid input should fail"); |
| } catch (Exception e) { |
| //ok |
| } |
| } |
| |
| /** |
| * Callback never made for authorization. Results of private table are |
| * returned withouth furhter checks. |
| * |
| * Test fails -> implemented correctly? |
| */ |
| public void testSet_authorizer() throws Exception { |
| TableResult resPriv = null; |
| TableResult resPub = null; |
| TableResult emptyTable = new TableResult(); |
| String insertPublic = "insert into public_table values(1,2)"; |
| String insertPrivate = "insert into private_table values(1,2)"; |
| // prepare, authorizer is not activated yet |
| db.exec("create table public_table(c1 integer, c2 integer);", null); |
| db.exec("create table private_table(c1 integer, c2 integer);", null); |
| // inserts |
| db.exec(insertPublic, null); |
| db.exec(insertPrivate, null); |
| // selects |
| resPriv = db.get_table("select * from private_table"); |
| resPub = db.get_table("select * from public_table"); |
| |
| // db.exec("delete from public_table where 1", null); |
| // TableResult emptyPubTable = db.exec("select * from public"); |
| |
| // set Authorizer (positive case): denies private table |
| AuthorizerCallback cb = new AuthorizerCallback(); |
| db.set_authorizer(cb); |
| //select |
| |
| db.exec("select * from private_table", cb); |
| assertTrue(cb.wasCalled()); |
| |
| /* |
| TableResult res = db.get_table("select * from private_table"); |
| assertEquals(emptyTable.toString(),res.toString()); |
| assertFalse(emptyTable.equals(resPriv)); |
| |
| res = db.get_table("select * from public_table"); |
| assertEquals(resPub,res); |
| */ |
| |
| // Try insert |
| try { |
| db.exec(insertPublic, null); |
| fail("authorization failed"); |
| } catch (Exception e) { |
| } |
| |
| try { |
| db.exec(insertPrivate, null); |
| fail("authorization failed"); |
| } catch (Exception e1) { |
| // ok |
| } |
| } |
| |
| public void testTrace() throws Exception { |
| String stmt = "create table TEST (res double);"; |
| TestTrace t = new TestTrace(); |
| assertFalse(t.traceCalled); |
| assertEquals(db.last_error(),Constants.SQLITE_OK); |
| db.trace((Trace) t); |
| db.exec(stmt,t); |
| assertTrue(t.traceCalled); |
| assertEquals(t.getTrace(),stmt); |
| |
| try { |
| db.close(); |
| db.exec(stmt,t); |
| fail("Exception Expected"); |
| } catch (Exception e) { |
| //ok |
| } |
| } |
| |
| public void testCompileString() throws Exception { |
| db.compile("select name from sqlite_master;"); |
| try { |
| db.compile("test"); |
| fail("Compiling of inaccurate statement does not fail."); |
| } catch (Exception e) { |
| } |
| } |
| |
| public void testCompileStringStringArray() throws Exception { |
| String args[] = new String[1]; |
| args[0] = "table"; |
| db.compile("select name from sqlite_master where type = '%q';",args); |
| |
| try { |
| db.compile("test",null); |
| fail("Compiling of inaccurate statement does not fail."); |
| } catch (Exception e) { |
| } |
| } |
| |
| public void testPrepare() throws Exception { |
| Stmt st = null; |
| Stmt st2 = null; |
| // test empty statement |
| try { |
| st = db.prepare(""); |
| assertEquals(0, st.bind_parameter_count()); |
| st.step(); |
| fail("stmt should not be prepared"); |
| } catch (Exception e) { |
| assertEquals("stmt already closed", e.getMessage()); |
| } |
| |
| // test statement with unbound arguments |
| try { |
| st2 = db.prepare("insert into " + DatabaseCreator.SIMPLE_TABLE1 |
| + " values (:one,:two,:three)"); |
| assertEquals(3, st2.bind_parameter_count()); |
| assertEquals(3, st2.bind_parameter_index(":three")); |
| assertEquals(":two", st2.bind_parameter_name(2)); |
| } finally { |
| st2.close(); |
| } |
| |
| try { |
| db.prepare("insert into " + DatabaseCreator.SIMPLE_TABLE1 |
| + " values(:one,:two,:three,:four);"); |
| } catch (Exception e) { |
| assertEquals("table " + DatabaseCreator.SIMPLE_TABLE1 |
| + " has 3 columns but 4 values were supplied", e |
| .getMessage()); |
| } |
| |
| try { |
| db.prepare("insert into " + DatabaseCreator.SIMPLE_TABLE1 |
| + " values(5, '10, 20);"); |
| } catch (Exception e) { |
| assertEquals("unrecognized token: \"'10, 20);\"", e.getMessage()); |
| } |
| |
| try { |
| db.prepare("insert into " + DatabaseCreator.SIMPLE_TABLE1 |
| + " values(5, 10 20);"); |
| } catch (Exception e) { |
| assertEquals("near \"20\": syntax error", e.getMessage()); |
| } |
| |
| } |
| |
| /** |
| * Not supported. |
| */ |
| public void testOpen_blob() throws Exception, java.lang.Exception { |
| Stmt statement2; |
| Blob blobInput = new Blob(); |
| |
| // Create test input Blob |
| InputStream inStream = null; |
| byte[] in = {(byte) 1, (byte) 2, (byte) 3, (byte) 4}; |
| |
| // setup test input |
| db.exec("create table TEST (res blob)",null); |
| inStream = Class.forName(this.getClass().getName()).getResourceAsStream("/blob.c"); |
| assertNotNull(inStream); |
| |
| // insert byte array in db |
| statement2 = db.prepare("insert into TEST(res) values (?)"); |
| statement2.bind(1, in); |
| statement2.step(); |
| statement2.close(); |
| |
| // read from db |
| Blob blob = db.open_blob(dbFile.getPath(), "TEST", "res", 1, true); |
| if (blob == null) { |
| fail("Blob could not be retrieved"); |
| } |
| //read from blob and compare values (positive case) |
| InputStream is = blob.getInputStream(); |
| |
| int i = 0; |
| int outByte = 0; |
| byte[] out = new byte[4]; |
| while ((outByte = is.read()) > -1) { |
| out[i] = (byte) outByte; |
| i++; |
| } |
| is.close(); |
| |
| blob.close(); |
| |
| assertTrue(Arrays.equals(in, out)); |
| |
| //read from blob and compare values (default blob) |
| db.exec("insert into TEST values(zeroblob(128))", null); |
| Blob blob2 = db.open_blob(dbFile.getPath(), "TEST", "res", 2, true); |
| is = blob2.getInputStream(); |
| for (i = 0; i < 128; i++) { |
| assertEquals(0, is.read()); |
| } |
| is.close(); |
| } |
| |
| public void testIs3() { |
| int ver = Integer.parseInt(db.version().substring(0,1)); |
| if (db.is3()) { |
| assertTrue( ver == 3); |
| } else { |
| assertTrue(ver != 3); |
| } |
| } |
| |
| public void testProgress_handler() throws Exception { |
| int inputVal = 3; |
| TestProgressHandler prog = new TestProgressHandler(); |
| db.exec("create table TEST5(id integer, firstname text, lastname text)",null); |
| Vm vm = db.compile("select * from TEST5; " |
| + "insert into TEST5 values(3, 'James', 'Bond'); " |
| + "delete from TEST5 where id = 3; " |
| + "select * from TEST5"); |
| int stmt = 0; |
| do { |
| ++stmt; |
| if (stmt > inputVal) { |
| db.progress_handler(inputVal, prog); |
| } else { |
| assertEquals(0, prog.getCounts()); |
| } |
| while (vm.step(prog)) { |
| } |
| } while (vm.compile()); |
| assertEquals(inputVal,prog.getCounts()); |
| |
| // Boundary value test |
| inputVal = 0; |
| TestProgressHandler progBoundary = new TestProgressHandler(); |
| db.progress_handler(inputVal, progBoundary); |
| Vm vm2 = db.compile("select * from TEST5; " |
| + "insert into TEST5 values(3, 'James', 'Bond'); " |
| + "delete from TEST5 where id = 3; " |
| + "select * from TEST5"); |
| do { |
| vm2.step(progBoundary); |
| } while (vm2.compile()); |
| assertEquals(inputVal, progBoundary.getCounts()); |
| |
| try { |
| db.exec("drop table TEST5",null); |
| } catch (Exception e) { |
| System.out.println(e.getMessage()); |
| e.printStackTrace(); |
| } |
| } |
| |
| class SinFunc implements Function { |
| public void function(FunctionContext fc, String args[]) { |
| Double d = new Double(args[0]); |
| fc.set_result(Math.sin(d.doubleValue())); |
| } |
| public void last_step(FunctionContext fc) {} |
| public void step(FunctionContext fc, String[] args) {} |
| } |
| |
| class TestTrace implements Trace,Callback { |
| |
| private StringBuffer buf = new StringBuffer(); |
| |
| public boolean traceCalled = false; |
| |
| public String getTrace() { |
| return buf.toString(); |
| } |
| |
| public void trace(String stmt) { |
| traceCalled = true; |
| buf.append(stmt); |
| } |
| |
| public void columns(String[] coldata) {} |
| |
| public boolean newrow(String[] rowdata) { |
| return false; |
| } |
| |
| public void types(String[] types) {} |
| } |
| |
| class AuthorizerCallback implements Authorizer, Callback { |
| |
| private boolean isAuthorizing = false; |
| |
| public boolean wasCalled() { |
| return isAuthorizing; |
| } |
| |
| public int authorize(int action, String arg1, String arg2, String arg3, |
| String arg4) { |
| Logger.global.info("DB authorization callback " + action + " " + arg1 + " " + arg2 + " " |
| + arg3 + " " + arg4 + " "); |
| this.isAuthorizing = true; |
| if (action != Constants.SQLITE_SELECT || arg1.contains("private_table")) { |
| return Constants.SQLITE_DENY; |
| } else { |
| return Constants.SQLITE_OK; |
| } |
| } |
| |
| public void columns(String[] coldata) {} |
| |
| public boolean newrow(String[] rowdata) { |
| return false; |
| } |
| |
| public void types(String[] types) {} |
| |
| } |
| |
| class TestBusyHandler implements BusyHandler, Callback { |
| |
| public boolean busy(String table, int count) { |
| return true; |
| } |
| |
| public void columns(String[] coldata) {} |
| |
| public boolean newrow(String[] rowdata) { |
| return false; |
| } |
| |
| public void types(String[] types) {} |
| } |
| |
| class TestProgressHandler implements ProgressHandler, Callback { |
| |
| private boolean progressed = false; |
| |
| private int counter = 0; |
| |
| public int getCounts() { |
| return counter; |
| } |
| |
| public boolean progress() { |
| this.progressed = true; |
| counter++; |
| return true; |
| } |
| |
| public void columns(String[] coldata) {} |
| |
| public boolean newrow(String[] rowdata) { |
| return false; |
| } |
| |
| public void types(String[] types) {} |
| } |
| |
| /** |
| * This method creates a Runnable that executes insert operation for the first table |
| */ |
| private static Runnable createTask2Interrupt(final int id, |
| final String dbName, final ErrorTracker errorTracker) { |
| return new Runnable() { |
| public void run() { |
| Database db = new Database(); |
| try { |
| String value = DatabaseCreator.defaultString + id; |
| |
| db.open(dbName, 0); |
| String insertQuery = "INSERT INTO " |
| + DatabaseCreator.TEST_TABLE1 |
| + " (id, field1, field2, field3) VALUES(" + id |
| + ", '" + value + "', " + id + ", " + id + ")"; |
| db.exec(insertQuery, null); |
| } catch (Exception e) { |
| errorTracker.registerException(this, e); |
| try { |
| db.interrupt(); |
| db.exec("DELETE FROM " + DatabaseCreator.SIMPLE_TABLE1 |
| + " WHERE id=" + id, null); |
| } catch (Exception e1) { |
| errorTracker.registerException(this, e1); |
| } |
| } |
| } |
| }; |
| } |
| |
| /** |
| * This method creates a Runnable that executes delete operation for the first table |
| */ |
| private static Runnable createTask1(final int id, final String dbName, |
| final ErrorTracker errorTracker) { |
| return new Runnable() { |
| public void run() { |
| try { |
| Database db = new Database(); |
| db.open(dbName, 0); |
| db.exec("DELETE FROM " |
| + DatabaseCreator.SIMPLE_TABLE1 + " WHERE id=" + id, null); |
| } catch (Exception e) { |
| errorTracker.registerException(this, e); |
| } |
| } |
| }; |
| } |
| |
| /** |
| * This method creates a Runnable that executes insert operation for the first table |
| */ |
| private static Runnable createTask2(final int id, final String dbName, |
| final ErrorTracker errorTracker) { |
| return new Runnable() { |
| public void run() { |
| try { |
| String value = DatabaseCreator.defaultString + id; |
| Database db = new Database(); |
| db.open(dbName, 0); |
| String insertQuery = "INSERT INTO " |
| + DatabaseCreator.TEST_TABLE1 |
| + " (id, field1, field2, field3) VALUES(" + id |
| + ", '" + value + "', " + id + ", " + id + ")"; |
| db.exec(insertQuery, null); |
| } catch (Exception e) { |
| errorTracker.registerException(this, e); |
| |
| } |
| } |
| }; |
| } |
| |
| /** |
| * This method creates a Runnable that executes update operation for the one record of the first |
| * table |
| */ |
| private static Runnable createTask3(final int oldID, final String dbName, |
| final int newID, final ErrorTracker errorTracker) { |
| return new Runnable() { |
| public void run() { |
| Database db = new Database(); |
| try { |
| db.open(dbName, 0); |
| String value = DatabaseCreator.defaultString + newID; |
| String updateQuery = "UPDATE " |
| + DatabaseCreator.TEST_TABLE1 + " SET id=" + newID |
| + ", field1='" + value + "', field2=" + newID |
| + ", field3=" + newID + " WHERE id=" + oldID; |
| db.exec(updateQuery, null); |
| } catch (Exception e) { |
| errorTracker.registerException(this, e); |
| } |
| } |
| }; |
| } |
| |
| private class ErrorTracker { |
| |
| private List<String> errors = new ArrayList<String>(); |
| |
| public void registerException(Runnable runnable, Exception e) { |
| System.out.println("Registered: " + e.getMessage()); |
| errors.add(e.getMessage()); |
| } |
| |
| public List<String> getErrors() { |
| return errors; |
| } |
| |
| public void reset() { |
| errors.clear(); |
| } |
| } |
| } |