Merge "Add sqlite3 changes APIs" into main
This commit is contained in:
@@ -176,6 +176,8 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
private static native void nativeCancel(long connectionPtr);
|
||||
private static native void nativeResetCancel(long connectionPtr, boolean cancelable);
|
||||
private static native int nativeLastInsertRowId(long connectionPtr);
|
||||
private static native long nativeChanges(long connectionPtr);
|
||||
private static native long nativeTotalChanges(long connectionPtr);
|
||||
|
||||
private SQLiteConnection(SQLiteConnectionPool pool,
|
||||
SQLiteDatabaseConfiguration configuration,
|
||||
@@ -1823,11 +1825,36 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
|
||||
* @return The ROWID of the last row to be inserted under this connection.
|
||||
* @hide
|
||||
*/
|
||||
long lastInsertRowId() {
|
||||
long getLastInsertRowId() {
|
||||
try {
|
||||
return nativeLastInsertRowId(mConnectionPtr);
|
||||
} finally {
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of database changes on the current connection made by the last SQL
|
||||
* statement
|
||||
* @hide
|
||||
*/
|
||||
long getLastChangedRowsCount() {
|
||||
try {
|
||||
return nativeChanges(mConnectionPtr);
|
||||
} finally {
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of database changes made on the current connection.
|
||||
* @hide
|
||||
*/
|
||||
long getTotalChangedRowsCount() {
|
||||
try {
|
||||
return nativeTotalChanges(mConnectionPtr);
|
||||
} finally {
|
||||
Reference.reachabilityFence(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2197,7 +2197,49 @@ public final class SQLiteDatabase extends SQLiteClosable {
|
||||
* @throws IllegalStateException if there is no current transaction.
|
||||
*/
|
||||
public long getLastInsertRowId() {
|
||||
return getThreadSession().lastInsertRowId();
|
||||
return getThreadSession().getLastInsertRowId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of database rows that were inserted, updated, or deleted by the most recent
|
||||
* SQL statement within the current transaction.
|
||||
*
|
||||
* @see <a href="https://sqlite.org/c3ref/changes.html">sqlite3_changes64</a>
|
||||
*
|
||||
* @return The number of rows changed by the most recent sql statement
|
||||
* @throws IllegalStateException if there is no current transaction.
|
||||
* @hide
|
||||
*/
|
||||
public long getLastChangedRowsCount() {
|
||||
return getThreadSession().getLastChangedRowsCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of database rows that have been inserted, updated, or deleted on
|
||||
* the current connection since it was created. Due to Android's internal management of
|
||||
* SQLite connections, the value may, or may not, include changes made in earlier
|
||||
* transactions. Best practice is to compare values returned within a single transaction.
|
||||
*
|
||||
* <code><pre>
|
||||
* database.beginTransaction();
|
||||
* try {
|
||||
* long initialValue = database.getTotalChangedRowsCount();
|
||||
* // Execute SQL statements
|
||||
* long changedRows = database.getTotalChangedRowsCount() - initialValue;
|
||||
* // changedRows counts the total number of rows updated in the transaction.
|
||||
* } finally {
|
||||
* database.endTransaction();
|
||||
* }
|
||||
* </pre></code>
|
||||
*
|
||||
* @see <a href="https://sqlite.org/c3ref/changes.html">sqlite3_total_changes64</a>
|
||||
*
|
||||
* @return The number of rows changed on the current connection.
|
||||
* @throws IllegalStateException if there is no current transaction.
|
||||
* @hide
|
||||
*/
|
||||
public long getTotalChangedRowsCount() {
|
||||
return getThreadSession().getTotalChangedRowsCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -988,9 +988,29 @@ public final class SQLiteSession {
|
||||
* necessary to acquire and release the connection: the connection has already been acquired.
|
||||
* @hide
|
||||
*/
|
||||
long lastInsertRowId() {
|
||||
long getLastInsertRowId() {
|
||||
throwIfNoTransaction();
|
||||
return mConnection.lastInsertRowId();
|
||||
return mConnection.getLastInsertRowId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of database rows that were changed by the most recent SQL statement on
|
||||
* this connection.
|
||||
* @hide
|
||||
*/
|
||||
long getLastChangedRowsCount() {
|
||||
throwIfNoTransaction();
|
||||
return mConnection.getLastChangedRowsCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of database rows that were changed on the current connection, since
|
||||
* it was created.
|
||||
* @hide
|
||||
*/
|
||||
long getTotalChangedRowsCount() {
|
||||
throwIfNoTransaction();
|
||||
return mConnection.getTotalChangedRowsCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -885,6 +885,16 @@ static jint nativeLastInsertRowId(JNIEnv* env, jclass, jlong connectionPtr) {
|
||||
return sqlite3_last_insert_rowid(connection->db);
|
||||
}
|
||||
|
||||
static jlong nativeChanges(JNIEnv* env, jclass, jlong connectionPtr) {
|
||||
SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
|
||||
return sqlite3_changes64(connection->db);
|
||||
}
|
||||
|
||||
static jlong nativeTotalChanges(JNIEnv* env, jclass, jlong connectionPtr) {
|
||||
SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
|
||||
return sqlite3_total_changes64(connection->db);
|
||||
}
|
||||
|
||||
static const JNINativeMethod sMethods[] =
|
||||
{
|
||||
/* name, signature, funcPtr */
|
||||
@@ -943,7 +953,9 @@ static const JNINativeMethod sMethods[] =
|
||||
{ "nativeResetCancel", "(JZ)V",
|
||||
(void*)nativeResetCancel },
|
||||
|
||||
{ "nativeLastInsertRowId", "(J)I", (void*) nativeLastInsertRowId }
|
||||
{ "nativeLastInsertRowId", "(J)I", (void*) nativeLastInsertRowId },
|
||||
{ "nativeChanges", "(J)J", (void*) nativeChanges },
|
||||
{ "nativeTotalChanges", "(J)J", (void*) nativeTotalChanges },
|
||||
};
|
||||
|
||||
int register_android_database_SQLiteConnection(JNIEnv *env)
|
||||
|
||||
@@ -137,4 +137,81 @@ public class SQLiteDatabaseTest {
|
||||
fail("Timed out");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a database with one table with three columns.
|
||||
*/
|
||||
private void createComplexDatabase() {
|
||||
mDatabase.beginTransaction();
|
||||
try {
|
||||
mDatabase.execSQL("CREATE TABLE t1 (i int, d double, t text);");
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A three-value insert for the complex database.
|
||||
*/
|
||||
private String createComplexInsert() {
|
||||
return "INSERT INTO t1 (i, d, t) VALUES (?1, ?2, ?3)";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutomaticCounters() {
|
||||
final int size = 10;
|
||||
|
||||
createComplexDatabase();
|
||||
|
||||
// Put 10 lines in the database.
|
||||
mDatabase.beginTransaction();
|
||||
try {
|
||||
try (SQLiteRawStatement s = mDatabase.createRawStatement(createComplexInsert())) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int vi = i * 3;
|
||||
double vd = i * 2.5;
|
||||
String vt = String.format("text%02dvalue", i);
|
||||
s.bindInt(1, vi);
|
||||
s.bindDouble(2, vd);
|
||||
s.bindText(3, vt);
|
||||
boolean r = s.step();
|
||||
// No row is returned by this query.
|
||||
assertFalse(r);
|
||||
s.reset();
|
||||
assertEquals(i + 1, mDatabase.getLastInsertRowId());
|
||||
assertEquals(1, mDatabase.getLastChangedRowsCount());
|
||||
assertEquals(i + 2, mDatabase.getTotalChangedRowsCount());
|
||||
}
|
||||
}
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
|
||||
// Put a second 10 lines in the database.
|
||||
mDatabase.beginTransaction();
|
||||
try {
|
||||
try (SQLiteRawStatement s = mDatabase.createRawStatement(createComplexInsert())) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int vi = i * 3;
|
||||
double vd = i * 2.5;
|
||||
String vt = String.format("text%02dvalue", i);
|
||||
s.bindInt(1, vi);
|
||||
s.bindDouble(2, vd);
|
||||
s.bindText(3, vt);
|
||||
boolean r = s.step();
|
||||
// No row is returned by this query.
|
||||
assertFalse(r);
|
||||
s.reset();
|
||||
assertEquals(size + i + 1, mDatabase.getLastInsertRowId());
|
||||
assertEquals(1, mDatabase.getLastChangedRowsCount());
|
||||
assertEquals(size + i + 2, mDatabase.getTotalChangedRowsCount());
|
||||
}
|
||||
}
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -845,59 +845,6 @@ public class SQLiteRawStatementTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLastInsertRowId() {
|
||||
final int size = 10;
|
||||
|
||||
createComplexDatabase();
|
||||
|
||||
// Put 10 lines in the database.
|
||||
mDatabase.beginTransaction();
|
||||
try {
|
||||
try (SQLiteRawStatement s = mDatabase.createRawStatement(createComplexInsert())) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int vi = i * 3;
|
||||
double vd = i * 2.5;
|
||||
String vt = String.format("text%02dvalue", i);
|
||||
s.bindInt(1, vi);
|
||||
s.bindDouble(2, vd);
|
||||
s.bindText(3, vt);
|
||||
boolean r = s.step();
|
||||
// No row is returned by this query.
|
||||
assertFalse(r);
|
||||
s.reset();
|
||||
assertEquals(i + 1, mDatabase.getLastInsertRowId());
|
||||
}
|
||||
}
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
|
||||
// Put a second 10 lines in the database.
|
||||
mDatabase.beginTransaction();
|
||||
try {
|
||||
try (SQLiteRawStatement s = mDatabase.createRawStatement(createComplexInsert())) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int vi = i * 3;
|
||||
double vd = i * 2.5;
|
||||
String vt = String.format("text%02dvalue", i);
|
||||
s.bindInt(1, vi);
|
||||
s.bindDouble(2, vd);
|
||||
s.bindText(3, vt);
|
||||
boolean r = s.step();
|
||||
// No row is returned by this query.
|
||||
assertFalse(r);
|
||||
s.reset();
|
||||
assertEquals(size + i + 1, mDatabase.getLastInsertRowId());
|
||||
}
|
||||
}
|
||||
mDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
mDatabase.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnicode() {
|
||||
// Create the t1 table and put some data in it.
|
||||
|
||||
Reference in New Issue
Block a user