Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8071ab46 authored by Lee Shombert's avatar Lee Shombert
Browse files

Expose SQLite deferred transactions as public API

Bug: 274020993

New public APIs are added to SQLiteDatabase:
beginTransactionDeferred() and beginTransactionWithListenerDeferred().
The listener parameter is nullable, so
beginTransactionWithListenerDeferred(nul) is strictly identical to
beginTransactionDeferred().

To maintain symmetry, existing beginTransactionWithListener*() APIs
have their listener parameter also marked nullable.  See the Anroid
API guidelines for this situation:

go/androidx-api-guidelines#extending-apis-that-are-missing-annotations

A CTS test will be added in a follow-on commit.

Test: atest
 * SQLiteDatabaseTest (from CtsDatabaseTestCases)

Change-Id: Icc94bf5bb058936cfa32d92a91379ddad3cea4b4
parent a150da57
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -14244,9 +14244,11 @@ package android.database.sqlite {
  public final class SQLiteDatabase extends android.database.sqlite.SQLiteClosable {
    method public void beginTransaction();
    method public void beginTransactionDeferred();
    method public void beginTransactionNonExclusive();
    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListener(@Nullable android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListenerDeferred(@Nullable android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListenerNonExclusive(@Nullable android.database.sqlite.SQLiteTransactionListener);
    method public android.database.sqlite.SQLiteStatement compileStatement(String) throws android.database.SQLException;
    method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
    method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
+65 −7
Original line number Diff line number Diff line
@@ -674,6 +674,30 @@ public final class SQLiteDatabase extends SQLiteClosable {
        beginTransaction(null /* transactionStatusCallback */, false);
    }

    /**
     * Begins a transaction in DEFERRED mode.
     * <p>
     * Transactions can be nested. When the outer transaction is ended all of the work done in
     * that transaction and all of the nested transactions will be committed or rolled back. The
     * changes will be rolled back if any transaction is ended without being marked as clean (by
     * calling setTransactionSuccessful). Otherwise they will be committed.
     * <p>
     * Here is the standard idiom for transactions:
     *
     * <pre>
     *   db.beginTransactionDeferred();
     *   try {
     *     ...
     *     db.setTransactionSuccessful();
     *   } finally {
     *     db.endTransaction();
     *   }
     * </pre>
     */
    public void beginTransactionDeferred() {
        beginTransactionWithListenerDeferred(null);
    }

    /**
     * Begins a transaction in EXCLUSIVE mode.
     * <p>
@@ -699,7 +723,8 @@ public final class SQLiteDatabase extends SQLiteClosable {
     * commits, or is rolled back, either explicitly or by a call to
     * {@link #yieldIfContendedSafely}.
     */
    public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
    public void beginTransactionWithListener(
            @Nullable SQLiteTransactionListener transactionListener) {
        beginTransaction(transactionListener, true);
    }

@@ -728,19 +753,53 @@ public final class SQLiteDatabase extends SQLiteClosable {
     *            explicitly or by a call to {@link #yieldIfContendedSafely}.
     */
    public void beginTransactionWithListenerNonExclusive(
            SQLiteTransactionListener transactionListener) {
            @Nullable SQLiteTransactionListener transactionListener) {
        beginTransaction(transactionListener, false);
    }

    /**
     * Begins a transaction in DEFERRED mode.
     * <p>
     * Transactions can be nested. When the outer transaction is ended all of the work done in
     * that transaction and all of the nested transactions will be committed or rolled back. The
     * changes will be rolled back if any transaction is ended without being marked as clean (by
     * calling setTransactionSuccessful). Otherwise they will be committed.
     * <p>
     * Here is the standard idiom for transactions:
     *
     * <pre>
     *   db.beginTransactionDeferred();
     *   try {
     *     ...
     *     db.setTransactionSuccessful();
     *   } finally {
     *     db.endTransaction();
     *   }
     * </pre>
     */
    public void beginTransactionWithListenerDeferred(
            @Nullable SQLiteTransactionListener transactionListener) {
        beginTransaction(transactionListener, SQLiteSession.TRANSACTION_MODE_DEFERRED);
    }

    @UnsupportedAppUsage
    private void beginTransaction(SQLiteTransactionListener transactionListener,
            boolean exclusive) {
        beginTransaction(transactionListener,
                exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
                SQLiteSession.TRANSACTION_MODE_IMMEDIATE);
    }

    /**
     * Begin a transaction with the specified mode.  Valid modes are
     * {@link SquLiteSession.TRANSACTION_MODE_DEFERRED},
     * {@link SquLiteSession.TRANSACTION_MODE_IMMEDIATE}, and
     * {@link SquLiteSession.TRANSACTION_MODE_EXCLUSIVE}.
     */
    private void beginTransaction(@Nullable SQLiteTransactionListener listener, int mode) {
        acquireReference();
        try {
            getThreadSession().beginTransaction(
                    exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
                            SQLiteSession.TRANSACTION_MODE_IMMEDIATE,
                    transactionListener,
            getThreadSession().beginTransaction(mode, listener,
                    getThreadDefaultConnectionFlags(false /*readOnly*/), null);
        } finally {
            releaseReference();
@@ -3113,4 +3172,3 @@ public final class SQLiteDatabase extends SQLiteClosable {
        ContentResolver.onDbCorruption(tag, message, stacktrace);
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -325,7 +325,12 @@ public final class SQLiteSession {
                        mConnection.execute("BEGIN EXCLUSIVE;", null,
                                cancellationSignal); // might throw
                        break;
                    case TRANSACTION_MODE_DEFERRED:
                        mConnection.execute("BEGIN DEFERRED;", null,
                                cancellationSignal); // might throw
                        break;
                    default:
                        // Per SQLite documentation, this executes in DEFERRED mode.
                        mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                        break;
                }