Add support for rawExecSQL, add tests for rawQuery binding, fts5, rtree, soundex, savepoint
This commit is contained in:
parent
20a8f57163
commit
6494035b17
@ -4,13 +4,16 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNull.nullValue;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase;
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabaseConfiguration;
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabaseCorruptException;
|
||||
import net.zetetic.database.sqlcipher.SQLiteException;
|
||||
import net.zetetic.database.sqlcipher.SQLiteStatement;
|
||||
|
||||
import org.hamcrest.core.Is;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
@ -98,7 +101,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void openExistingSQLCipherDatabaseWithStringPassword(){
|
||||
public void openExistingSQLCipherDatabaseWithStringPassword() {
|
||||
File databasePath = null;
|
||||
int a = 0, b = 0;
|
||||
try {
|
||||
@ -106,7 +109,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
databasePath = extractAssetToDatabaseDirectory("sqlcipher-4.x-testkey.db");
|
||||
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "testkey", null, SQLiteDatabase.OPEN_READWRITE, null);
|
||||
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
|
||||
if(cursor != null && cursor.moveToFirst()){
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
a = cursor.getInt(0);
|
||||
b = cursor.getInt(1);
|
||||
cursor.close();
|
||||
@ -119,7 +122,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void openExistingSQLCipherDatabaseWithByteArrayPassword(){
|
||||
public void openExistingSQLCipherDatabaseWithByteArrayPassword() {
|
||||
File databasePath = null;
|
||||
int a = 0, b = 0;
|
||||
try {
|
||||
@ -127,7 +130,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
databasePath = extractAssetToDatabaseDirectory("sqlcipher-4.x-testkey.db");
|
||||
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "testkey".getBytes(StandardCharsets.UTF_8), null, SQLiteDatabase.OPEN_READWRITE, null);
|
||||
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
|
||||
if(cursor != null && cursor.moveToFirst()){
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
a = cursor.getInt(0);
|
||||
b = cursor.getInt(1);
|
||||
cursor.close();
|
||||
@ -140,7 +143,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void openExistingSQLitePlaintextDatabase(){
|
||||
public void openExistingSQLitePlaintextDatabase() {
|
||||
File databasePath = null;
|
||||
int a = 0, b = 0;
|
||||
try {
|
||||
@ -148,7 +151,7 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
databasePath = extractAssetToDatabaseDirectory("sqlite-plaintext.db");
|
||||
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "", null, SQLiteDatabase.OPEN_READWRITE, null);
|
||||
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
|
||||
if(cursor != null && cursor.moveToFirst()){
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
a = cursor.getInt(0);
|
||||
b = cursor.getInt(1);
|
||||
cursor.close();
|
||||
@ -237,4 +240,161 @@ public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
|
||||
database = SQLiteDatabase.openOrCreateDatabase(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, "foo", null, null, null);
|
||||
database.changePassword("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithBoolean() {
|
||||
boolean a = false, b = true;
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{true, false});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", false);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
a = cursor.getInt(0) > 0;
|
||||
b = cursor.getInt(1) > 0;
|
||||
}
|
||||
assertThat(a, is(true));
|
||||
assertThat(b, is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithByteArray() {
|
||||
byte[] a = generateRandomBytes(64);
|
||||
byte[] b = generateRandomBytes(64);
|
||||
byte[] aActual = null, bActual = null;
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{a, b});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", b);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
aActual = cursor.getBlob(0);
|
||||
bActual = cursor.getBlob(1);
|
||||
}
|
||||
assertThat(aActual, is(a));
|
||||
assertThat(bActual, is(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithDouble() {
|
||||
double a = 3.14d, b = 42.0d;
|
||||
double aActual = 0.0d, bActual = 0.0d;
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{a, b});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", b);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
aActual = cursor.getDouble(0);
|
||||
bActual = cursor.getDouble(1);
|
||||
}
|
||||
assertThat(aActual, is(a));
|
||||
assertThat(bActual, is(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithFloat() {
|
||||
float a = 3.14f, b = 42.0f;
|
||||
float aActual = 0.0f, bActual = 0.0f;
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{a, b});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", b);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
aActual = cursor.getFloat(0);
|
||||
bActual = cursor.getFloat(1);
|
||||
}
|
||||
assertThat(aActual, is(a));
|
||||
assertThat(bActual, is(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithLong() {
|
||||
long a = 3L, b = 42L;
|
||||
long aActual = 0L, bActual = 0L;
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{a, b});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", b);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
aActual = cursor.getLong(0);
|
||||
bActual = cursor.getLong(1);
|
||||
}
|
||||
assertThat(aActual, is(a));
|
||||
assertThat(bActual, is(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRawQueryWithString() {
|
||||
String a = "one for the money", b = "two for the show";
|
||||
String aActual = "", bActual = "";
|
||||
database.execSQL("create table t1(a,b);");
|
||||
database.execSQL("insert into t1(a,b) values(?, ?);", new Object[]{a, b});
|
||||
Cursor cursor = database.rawQuery("select * from t1 where b = ?;", b);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
aActual = cursor.getString(0);
|
||||
bActual = cursor.getString(1);
|
||||
}
|
||||
assertThat(aActual, is(a));
|
||||
assertThat(bActual, is(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformFTS5Search() {
|
||||
boolean found = false;
|
||||
database.execSQL("CREATE VIRTUAL TABLE email USING fts5(sender, title, body);");
|
||||
database.execSQL("insert into email(sender, title, body) values(?, ?, ?);",
|
||||
new Object[]{"foo@bar.com", "Test Email", "This is a test email message."});
|
||||
Cursor cursor = database.rawQuery("select * from email where email match ?;", "test");
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
found = cursor.getString(cursor.getColumnIndex("sender")).equals("foo@bar.com");
|
||||
}
|
||||
assertThat(found, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRTreeTest() {
|
||||
int id = 0;
|
||||
String create = "CREATE VIRTUAL TABLE demo_index USING rtree(id, minX, maxX, minY, maxY);";
|
||||
String insert = "INSERT INTO demo_index VALUES(?, ?, ?, ?, ?);";
|
||||
database.execSQL(create);
|
||||
database.execSQL(insert, new Object[]{1, -80.7749, -80.7747, 35.3776, 35.3778});
|
||||
Cursor cursor = database.rawQuery("SELECT * FROM demo_index WHERE maxY < ?;", 36);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
id = cursor.getInt(0);
|
||||
cursor.close();
|
||||
}
|
||||
assertThat(id, is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformSoundexTest() {
|
||||
String value = "";
|
||||
Cursor cursor = database.rawQuery("SELECT soundex('sqlcipher');");
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
value = cursor.getString(0);
|
||||
cursor.close();
|
||||
}
|
||||
assertThat(value, is("S421"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInsertWithOnConflictTest(){
|
||||
database.execSQL("create table user(_id integer primary key autoincrement, email text unique not null);");
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("email", "foo@bar.com");
|
||||
long id = database.insertWithOnConflict("user", null, values,
|
||||
SQLiteDatabase.CONFLICT_IGNORE);
|
||||
long error = database.insertWithOnConflict("user", null, values,
|
||||
SQLiteDatabase.CONFLICT_IGNORE);
|
||||
assertThat(id, is(1L));
|
||||
assertThat(error, is(-1L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPerformRollbackToSavepoint(){
|
||||
database.rawExecSQL("savepoint foo;");
|
||||
database.rawExecSQL("create table t1(a,b);");
|
||||
database.rawExecSQL("insert into t1(a,b) values(?,?);", "one for the money", "two for the show");
|
||||
database.rawExecSQL("savepoint bar;");
|
||||
database.rawExecSQL("insert into t1(a,b) values(?,?);", "three to get ready", "go man go");
|
||||
database.rawExecSQL("rollback transaction to bar;");
|
||||
database.rawExecSQL("commit;");
|
||||
SQLiteStatement statement = database.compileStatement("select count(*) from t1 where a = ?;");
|
||||
statement.bindString(1, "one for the money");
|
||||
long count = statement.simpleQueryForLong();
|
||||
assertThat(count, is(1L));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1856,6 +1856,28 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
executeSql(sql, bindArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a statement that returns a count of the number of rows
|
||||
* that were changed. No transaction state checking is performed.
|
||||
* @param sql The SQL statement to execute.
|
||||
* @param bindArgs The arguments to bind.
|
||||
* @return The number of rows that were changed.
|
||||
*/
|
||||
public int rawExecSQL(String sql, Object...bindArgs) throws SQLException {
|
||||
acquireReference();
|
||||
try {
|
||||
SQLiteStatement statement = new SQLiteStatement(this, sql, bindArgs);
|
||||
try {
|
||||
return statement.executeUpdateDeleteRaw();
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
|
||||
} finally {
|
||||
releaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
private int executeSql(String sql, Object[] bindArgs) throws SQLException {
|
||||
acquireReference();
|
||||
try {
|
||||
|
||||
@ -762,6 +762,37 @@ public final class SQLiteSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a statement that returns a count of the number of rows
|
||||
* that were changed. Use for UPDATE or DELETE SQL statements. Does not
|
||||
* perform additional transaction process verification.
|
||||
*
|
||||
* @param sql The SQL statement to execute.
|
||||
* @param bindArgs The arguments to bind, or null if none.
|
||||
* @param connectionFlags The connection flags to use if a connection must be
|
||||
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
|
||||
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
|
||||
* @return The number of rows that were changed.
|
||||
*
|
||||
* @throws SQLiteException if an error occurs, such as a syntax error
|
||||
* or invalid number of bind arguments.
|
||||
* @throws OperationCanceledException if the operation was canceled.
|
||||
*/
|
||||
public int executeForChangedRowCountRaw(String sql, Object[] bindArgs, int connectionFlags,
|
||||
CancellationSignal cancellationSignal) {
|
||||
if (sql == null) {
|
||||
throw new IllegalArgumentException("sql must not be null.");
|
||||
}
|
||||
|
||||
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
|
||||
try {
|
||||
return mConnection.executeForChangedRowCount(sql, bindArgs,
|
||||
cancellationSignal); // might throw
|
||||
} finally {
|
||||
releaseConnection(); // might throw
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a statement that returns the row id of the last row inserted
|
||||
* by the statement. Use for INSERT SQL statements.
|
||||
|
||||
@ -75,6 +75,27 @@ public final class SQLiteStatement extends SQLiteProgram {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this SQL statement, if the the number of rows affected by execution of this SQL
|
||||
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
|
||||
* No transaction state checking is performed.
|
||||
* @return the number of rows affected by this SQL statement execution.
|
||||
* @throws android.database.SQLException If the SQL string is invalid for
|
||||
* some reason
|
||||
*/
|
||||
public int executeUpdateDeleteRaw() {
|
||||
acquireReference();
|
||||
try {
|
||||
return getSession().executeForChangedRowCountRaw(
|
||||
getSql(), getBindArgs(), getConnectionFlags(), null);
|
||||
} catch (SQLiteDatabaseCorruptException ex) {
|
||||
onCorruption();
|
||||
throw ex;
|
||||
} finally {
|
||||
releaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this SQL statement and return the ID of the row inserted due to this call.
|
||||
* The SQL statement should be an INSERT for this to be a useful call.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user