blob: f2cbc5717607ebdfe6c897382fab34c90737b562 [file] [log] [blame]
/*
* 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();
}
}
}