SQLite Android Bindings

Check-in [bd77d855a1]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Support for loadable extension to be ensabled/disabled by functions on SQLiteDatabase and flag on openDatabase()
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | api-level-9
Files: files | file ages | folders
SHA1: bd77d855a1b28e89a996f6de8fdd6e27843b5bb9
User & Date: pjw 2017-05-02 12:45:35.408
Context
2017-05-02
14:39
Throw SQLiteMisuseException if built with SQLITE_OMIT_LOAD_EXTENSION and client attempts to enable extension load (check-in: 566a4f756b user: pjw tags: api-level-9)
12:45
Support for loadable extension to be ensabled/disabled by functions on SQLiteDatabase and flag on openDatabase() (check-in: bd77d855a1 user: pjw tags: api-level-9)
06:27
Fix remnant API 11 code and remove unused cruft from DatabaseUtils (check-in: dafd530d60 user: pjw tags: api-level-9)
Changes
Unified Diff Ignore Whitespace Patch
Changes to sqlite3/src/main/java/org/sqlite/database/sqlite/SQLiteConnection.java.
161
162
163
164
165
166
167


168
169
170
171
172
173
174
            long connectionPtr, long statementPtr, CursorWindow win,
            int startPos, int requiredPos, boolean countAllRows);
    private static native int nativeGetDbLookaside(long connectionPtr);
    private static native void nativeCancel(long connectionPtr);
    private static native void nativeResetCancel(long connectionPtr, boolean cancelable);

    private static native boolean nativeHasCodec();


    public static boolean hasCodec(){ return nativeHasCodec(); }

    private SQLiteConnection(SQLiteConnectionPool pool,
            SQLiteDatabaseConfiguration configuration,
            int connectionId, boolean primaryConnection) {
        mPool = pool;
        mConfiguration = new SQLiteDatabaseConfiguration(configuration);







>
>







161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
            long connectionPtr, long statementPtr, CursorWindow win,
            int startPos, int requiredPos, boolean countAllRows);
    private static native int nativeGetDbLookaside(long connectionPtr);
    private static native void nativeCancel(long connectionPtr);
    private static native void nativeResetCancel(long connectionPtr, boolean cancelable);

    private static native boolean nativeHasCodec();
    private static native void nativeEnableLoadExtension(long connectionPtr, boolean enable);

    public static boolean hasCodec(){ return nativeHasCodec(); }

    private SQLiteConnection(SQLiteConnectionPool pool,
            SQLiteDatabaseConfiguration configuration,
            int connectionId, boolean primaryConnection) {
        mPool = pool;
        mConfiguration = new SQLiteDatabaseConfiguration(configuration);
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
        mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
                mConfiguration.label,
                SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);

        setPageSize();
        setForeignKeyModeFromConfiguration();
        setJournalSizeLimit();
	setAutoCheckpointInterval();
	if( !nativeHasCodec() ){
	  setWalModeFromConfiguration();
          setLocaleFromConfiguration();
	}


        // Register custom functions.
        final int functionCount = mConfiguration.customFunctions.size();
        for (int i = 0; i < functionCount; i++) {
            SQLiteCustomFunction function = mConfiguration.customFunctions.get(i);
            nativeRegisterCustomFunction(mConnectionPtr, function);
        }







|
|
|
|
|
>







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
        mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
                mConfiguration.label,
                SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);

        setPageSize();
        setForeignKeyModeFromConfiguration();
        setJournalSizeLimit();
        setAutoCheckpointInterval();
        if( !nativeHasCodec() ){
            setWalModeFromConfiguration();
            setLocaleFromConfiguration();
        }
        setLoadExtensionFromConfiguration();

        // Register custom functions.
        final int functionCount = mConfiguration.customFunctions.size();
        for (int i = 0; i < functionCount; i++) {
            SQLiteCustomFunction function = mConfiguration.customFunctions.get(i);
            nativeRegisterCustomFunction(mConnectionPtr, function);
        }
304
305
306
307
308
309
310









311
312
313
314
315
316
317
                setSyncMode(SQLiteGlobal.getWALSyncMode());
            } else {
                setJournalMode(SQLiteGlobal.getDefaultJournalMode());
                setSyncMode(SQLiteGlobal.getDefaultSyncMode());
            }
        }
    }










    private void setSyncMode(String newValue) {
        String value = executeForString("PRAGMA synchronous", null, null);
        if (!canonicalizeSyncMode(value).equalsIgnoreCase(
                canonicalizeSyncMode(newValue))) {
            execute("PRAGMA synchronous=" + newValue, null, null);
        }







>
>
>
>
>
>
>
>
>







307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
                setSyncMode(SQLiteGlobal.getWALSyncMode());
            } else {
                setJournalMode(SQLiteGlobal.getDefaultJournalMode());
                setSyncMode(SQLiteGlobal.getDefaultSyncMode());
            }
        }
    }

    // NOTE: Extension for sqlite.org bindings
    private void setLoadExtensionFromConfiguration() {
        if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_LOAD_EXTENSION) != 0) {
            nativeEnableLoadExtension(mConnectionPtr, true);
        } else {
            nativeEnableLoadExtension(mConnectionPtr, false);
        }
    }

    private void setSyncMode(String newValue) {
        String value = executeForString("PRAGMA synchronous", null, null);
        if (!canonicalizeSyncMode(value).equalsIgnoreCase(
                canonicalizeSyncMode(newValue))) {
            execute("PRAGMA synchronous=" + newValue, null, null);
        }
428
429
430
431
432
433
434



435
436
437
438
439
440
441

        // Remember what changed.
        boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
                != mConfiguration.foreignKeyConstraintsEnabled;
        boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
                & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
        boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);




        // Update configuration parameters.
        mConfiguration.updateParametersFrom(configuration);

        // Update prepared statement cache size.
        /* mPreparedStatementCache.resize(configuration.maxSqlCacheSize); */








>
>
>







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

        // Remember what changed.
        boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
                != mConfiguration.foreignKeyConstraintsEnabled;
        boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
                & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
        boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
        // NOTE: Extension for sqlite.org bindings
        boolean loadExtSqlChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
                & SQLiteDatabase.ENABLE_LOAD_EXTENSION) != 0;

        // Update configuration parameters.
        mConfiguration.updateParametersFrom(configuration);

        // Update prepared statement cache size.
        /* mPreparedStatementCache.resize(configuration.maxSqlCacheSize); */

449
450
451
452
453
454
455





456
457
458
459
460
461
462
            setWalModeFromConfiguration();
        }

        // Update locale.
        if (localeChanged) {
            setLocaleFromConfiguration();
        }





    }

    // Called by SQLiteConnectionPool only.
    // When set to true, executing write operations will throw SQLiteException.
    // Preparing statements that might write is ok, just don't execute them.
    void setOnlyAllowReadOnlyOperations(boolean readOnly) {
        mOnlyAllowReadOnlyOperations = readOnly;







>
>
>
>
>







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
            setWalModeFromConfiguration();
        }

        // Update locale.
        if (localeChanged) {
            setLocaleFromConfiguration();
        }

        // Update LOAD_EXTENSIONS support (sqlite.org extension)
        if (loadExtSqlChanged) {
            setLoadExtensionFromConfiguration();
        }
    }

    // Called by SQLiteConnectionPool only.
    // When set to true, executing write operations will throw SQLiteException.
    // Preparing statements that might write is ok, just don't execute them.
    void setOnlyAllowReadOnlyOperations(boolean readOnly) {
        mOnlyAllowReadOnlyOperations = readOnly;
Changes to sqlite3/src/main/java/org/sqlite/database/sqlite/SQLiteDatabase.java.
34
35
36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
import org.sqlite.os.OperationCanceledException;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Printer;

import org.sqlite.database.sqlite.CloseGuard;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.HashMap;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;

/**







<
<




>







34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
import org.sqlite.os.OperationCanceledException;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Printer;



import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;

/**
246
247
248
249
250
251
252










253
254
255
256
257
258
259
     * Write-ahead logging cannot be used with read-only databases so the value of
     * this flag is ignored if the database is opened read-only.
     *
     * @see #enableWriteAheadLogging
     */
    public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;











    /**
     * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
     *
     * Each prepared-statement is between 1K - 6K, depending on the complexity of the
     * SQL statement & schema.  A large SQL cache may use a significant amount of memory.
     */
    public static final int MAX_SQL_CACHE_SIZE = 100;







>
>
>
>
>
>
>
>
>
>







245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
     * Write-ahead logging cannot be used with read-only databases so the value of
     * this flag is ignored if the database is opened read-only.
     *
     * @see #enableWriteAheadLogging
     */
    public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;

    /**
     * NOTE: THIS IS AN ADDITION TO THE INTERFACE FOR THE SQLITE.ORG BINDINGS.
     *
     * Open flag: Flag for {@link #openDatabase} to specify that loadable extensions
     * should be allowed via SQL or API.
     *
     * @see #enableLoadExtension
     */
    public static final int ENABLE_LOAD_EXTENSION = 0x01000000;

    /**
     * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
     *
     * Each prepared-statement is between 1K - 6K, depending on the complexity of the
     * SQL statement & schema.  A large SQL cache may use a significant amount of memory.
     */
    public static final int MAX_SQL_CACHE_SIZE = 100;
2007
2008
2009
2010
2011
2012
2013











































































2014
2015
2016
2017
2018
2019
2020
    public boolean isWriteAheadLoggingEnabled() {
        synchronized (mLock) {
            throwIfNotOpenLocked();

            return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
        }
    }












































































    /**
     * Collect statistics about all open databases in the current process.
     * Used by bug report.
     */
    static ArrayList<DbStats> getDbStats() {
        ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
    public boolean isWriteAheadLoggingEnabled() {
        synchronized (mLock) {
            throwIfNotOpenLocked();

            return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
        }
    }

    /**
     * NOTE: THIS IS AN ADDITION TO THE INTERFACE FOR THE SQLITE.ORG BINDINGS.
     *
     * This method will enable the Load_Extension SQL function and related API call.
     *
     * Note that it is more efficient to enable this as part of the open flags.
     *
     * @return true if successful or already enabled.
     * @see #ENABLE_LOAD_EXTENSION
     */
    public boolean enableLoadExtension() {
        synchronized (mLock) {
            throwIfNotOpenLocked();

            if ((mConfigurationLocked.openFlags & ENABLE_LOAD_EXTENSION) != 0) {
                return true;
            }

            mConfigurationLocked.openFlags |= ENABLE_LOAD_EXTENSION;
            try {
                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
            } catch (RuntimeException ex) {
                mConfigurationLocked.openFlags &= ~ENABLE_LOAD_EXTENSION;
                throw ex;
            }
        }
        return true;
    }

    /**
     * NOTE: THIS IS AN ADDITION TO THE INTERFACE FOR THE SQLITE.ORG BINDINGS.
     *
     * This method will disable the Load_Extension SQL function and related API call.
     *
     * @return true if successful or already enabled.
     *
     * @see #enableLoadExtension()
     * @see #ENABLE_LOAD_EXTENSION
     */
    public void disableLoadExtension() {
        synchronized (mLock) {
            throwIfNotOpenLocked();

            if ((mConfigurationLocked.openFlags & ENABLE_LOAD_EXTENSION) == 0) {
                return;
            }

            mConfigurationLocked.openFlags &= ~ENABLE_LOAD_EXTENSION;
            try {
                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
            } catch (RuntimeException ex) {
                mConfigurationLocked.openFlags |= ENABLE_LOAD_EXTENSION;
                throw ex;
            }
        }
    }

    /**
     * NOTE: THIS IS AN ADDITION TO THE INTERFACE FOR THE SQLITE.ORG BINDINGS.
     *
     * Returns true if loading extensions has been enabled for this database.
     *
     * @return True if loading extensions has been enabled for this database.
     *
     * @see #enableLoadExtension()
     * @see #ENABLE_LOAD_EXTENSION
     */
    public boolean isLoadExtensionEnabled() {
        synchronized (mLock) {
            throwIfNotOpenLocked();

            return (mConfigurationLocked.openFlags & ENABLE_LOAD_EXTENSION) != 0;
        }
    }

    /**
     * Collect statistics about all open databases in the current process.
     * Used by bug report.
     */
    static ArrayList<DbStats> getDbStats() {
        ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
Changes to sqlite3/src/main/jni/sqlite/android_database_SQLiteConnection.cpp.
853
854
855
856
857
858
859






860
861
862
863
864
865
866
    if (cancelable) {
        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
                connection);
    } else {
        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
    }
}







static jboolean nativeHasCodec(JNIEnv* env, jobject clazz){
#ifdef SQLITE_HAS_CODEC
  return true;
#else
  return false;
#endif







>
>
>
>
>
>







853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
    if (cancelable) {
        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
                connection);
    } else {
        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
    }
}

/** NOTE: Extension for sqlite.org bindings */
static void nativeEnableLoadExtension(JNIEnv* env, jobject clazz, jlong connectionPtr, jboolean enable) {
    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
    sqlite3_enable_load_extension(connection->db, enable ? 1 : 0);
}

static jboolean nativeHasCodec(JNIEnv* env, jobject clazz){
#ifdef SQLITE_HAS_CODEC
  return true;
#else
  return false;
#endif
918
919
920
921
922
923
924


925
926
927
928
929
930
931
            (void*)nativeExecuteForCursorWindow },
    { "nativeGetDbLookaside", "(J)I",
            (void*)nativeGetDbLookaside },
    { "nativeCancel", "(J)V",
            (void*)nativeCancel },
    { "nativeResetCancel", "(JZ)V",
            (void*)nativeResetCancel },



    { "nativeHasCodec", "()Z", (void*)nativeHasCodec },
};

#define FIND_CLASS(var, className) \
        var = env->FindClass(className); \
        LOG_FATAL_IF(! var, "Unable to find class " className);







>
>







924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
            (void*)nativeExecuteForCursorWindow },
    { "nativeGetDbLookaside", "(J)I",
            (void*)nativeGetDbLookaside },
    { "nativeCancel", "(J)V",
            (void*)nativeCancel },
    { "nativeResetCancel", "(JZ)V",
            (void*)nativeResetCancel },
    { "nativeEnableLoadExtension", "(JZ)V",
            (void*)nativeEnableLoadExtension },

    { "nativeHasCodec", "()Z", (void*)nativeHasCodec },
};

#define FIND_CLASS(var, className) \
        var = env->FindClass(className); \
        LOG_FATAL_IF(! var, "Unable to find class " className);