Search code examples
androidsqliteandroid-room

execute "PRAGMA compile_options" output nothing on Android SQLite


I am using sqlite on Android,how can I get the compile_options on Android Sqlite inside the OS

private fun getChunkSizeFromSqlite() { val db = BundleStorageProvider.getDb(mPlatformType) ?: return

val cursor = db.query("PRAGMA compile_options")
while (cursor.moveToNext()) {
  val compileOption = cursor.getString(0)
  KxbLog.i("hello", compileOption)
}

Solution

  • how can I get the compile_options on Android Sqlite inside the OS

    I don't believe that you can as it would appear that the compilation used has the SQLITE_OMIT_COMPILEOPTION_DIAGS option.

    More specifically consider the following functions (basically the same BUT one for use against an SQLiteDatabase (non room), the other against a SupportSQLiteDatabase (Room)):-

        private fun getCompileTimeOptions(db: SQLiteDatabase) {
            try {
                val sb = StringBuilder()
                for (i in 1..10) {
                    val csr = db.rawQuery(" SELECT sqlite_compileoption_get(${i})",null)
                    while (csr.moveToNext()) {
                        sb.append("Compile Option ${i} is ${csr.getString(0)}")
                    }
                    csr.close()
                }
                Log.d(TAG, sb.toString())
            } catch (e: Exception) {
                Log.d(TAG,"Exception Caught: ${e.cause}")
            }
            try {
                var csr = db.rawQuery("PRAGMA compile_options",null)
                DatabaseUtils.dumpCursor(csr)
                csr = db.rawQuery("SELECT * FROM pragma_compile_options",null)
                DatabaseUtils.dumpCursor(csr)
                csr.close()
    
            } catch (e: Exception) {
                Log.d(TAG,"Exception Caught: ${e.cause}")
            }
        }
        private fun getCompileOptions(db: SupportSQLiteDatabase) {
            try {
                val sb = StringBuilder()
                for (i in 1..10) {
                    val csr = db.query(" SELECT sqlite_compileoption_get(${i})")
                    while (csr.moveToNext()) {
                        sb.append("Compile Option ${i} is ${csr.getString(0)}")
                    }
                    csr.close()
                }
                Log.d(TAG, sb.toString())
            } catch (e: Exception) {
                Log.d(TAG,"Exception Caught: ${e.cause}")
            }
            try {
    
                var csr = db.query("PRAGMA compile_options")
                DatabaseUtils.dumpCursor(csr)
                csr = db.query("SELECT * FROM pragma_compile_options")
                DatabaseUtils.dumpCursor(csr)
                csr.close()
            } catch (e: Exception) {
                Log.d(TAG,"Exception Caught: ${e.cause}")
            }
        }
    

    The first function is called prior to the Room databaseBuilder being invoked after retrieving the database via:-

        fun preOpenSchemaDump(context: Context) {
            if (context.getDatabasePath(DB_NAME).exists()) {
                val db = SQLiteDatabase.openDatabase(
                    context.getDatabasePath(DB_NAME).path,
                    null,
                    SQLiteDatabase.OPEN_READWRITE
                )
                Log.d(TAG,"Database Version is ${db.version}: Room version will be ${DB_VERSION}" )
                dumpSchema("PreOpen invoked", db)
                getCompileTimeOptions(db) /*<<<<<<<<<<*/
                db.close()
            } else {
                Log.d(TAG,"PreOpen Invoked but Database does not exist yet (nothing to dump so skipped)")
            }
        }
    

    The second function is called, via a CallBack, in the overidden onOpen and onCreate methods.

    All are handled within the function that returns an instance of the @Database annotated class, as per:-

        fun getInstance(context: Context): RoomDatabaseImpl {
            if (instance==null) {
                preOpenSchemaDump(context) /*<<<<<<<<<< */
                instance= Room.databaseBuilder(context,RoomDatabaseImpl::class.java, DB_NAME)
                    .allowMainThreadQueries() /* For brevity */
                    .addCallback(CB) /* added for debugging */ /* <<<<<<<<<< */
                    .addMigrations(Migration1To2,Migration2To3,Migration3To4)
                    .build()
            }
            return instance as RoomDatabaseImpl
        }
    

    As can be seen both functions try to get the compile time options via 3 methods

    1. via the sqlite_compileoption_get scalar function
    2. via the COMPILE_OPTIONS PRAGMA
    3. via table-valued version of the PRAGMA i.e. SELECT * FROM pragma_compile_options

    The results are that an invocation (irrespective of whether called via an SQLiteDatabase object or a SupportSQLiteDatabase object) along the lines of:-

    2024-04-27 11:00:18.698 D/DBINFO: PreOpen invoked - dumping schema to log:-
    2024-04-27 11:00:18.699 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@aa6612
    2024-04-27 11:00:18.699 I/System.out: 0 {
    2024-04-27 11:00:18.699 I/System.out:    type=table
    2024-04-27 11:00:18.699 I/System.out:    name=android_metadata
    2024-04-27 11:00:18.699 I/System.out:    tbl_name=android_metadata
    2024-04-27 11:00:18.699 I/System.out:    rootpage=3
    2024-04-27 11:00:18.700 I/System.out:    sql=CREATE TABLE android_metadata (locale TEXT)
    2024-04-27 11:00:18.700 I/System.out: }
    2024-04-27 11:00:18.700 I/System.out: 1 {
    2024-04-27 11:00:18.700 I/System.out:    type=table
    2024-04-27 11:00:18.700 I/System.out:    name=project
    2024-04-27 11:00:18.700 I/System.out:    tbl_name=project
    2024-04-27 11:00:18.700 I/System.out:    rootpage=4
    2024-04-27 11:00:18.700 I/System.out:    sql=CREATE TABLE `project` (`id` TEXT NOT NULL, `uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `startDate` TEXT, `endDate` TEXT, `venueName` TEXT, `timeZone` TEXT, `scheduledAnonymisationDate` TEXT, `nfcCollectorId` TEXT, `nfcMerchantId` TEXT, `nfcPrivateKey` TEXT, `nfcProfileId` TEXT, PRIMARY KEY(`id`))
    2024-04-27 11:00:18.700 I/System.out: }
    2024-04-27 11:00:18.700 I/System.out: 2 {
    2024-04-27 11:00:18.700 I/System.out:    type=index
    2024-04-27 11:00:18.700 I/System.out:    name=sqlite_autoindex_project_1
    2024-04-27 11:00:18.701 I/System.out:    tbl_name=project
    2024-04-27 11:00:18.701 I/System.out:    rootpage=5
    2024-04-27 11:00:18.701 I/System.out:    sql=null
    2024-04-27 11:00:18.701 I/System.out: }
    2024-04-27 11:00:18.701 I/System.out: 3 {
    2024-04-27 11:00:18.701 I/System.out:    type=index
    2024-04-27 11:00:18.701 I/System.out:    name=index_project_uuid
    2024-04-27 11:00:18.701 I/System.out:    tbl_name=project
    2024-04-27 11:00:18.701 I/System.out:    rootpage=6
    2024-04-27 11:00:18.701 I/System.out:    sql=CREATE INDEX `index_project_uuid` ON `project` (`uuid`)
    2024-04-27 11:00:18.701 I/System.out: }
    2024-04-27 11:00:18.701 I/System.out: 4 {
    2024-04-27 11:00:18.701 I/System.out:    type=table
    2024-04-27 11:00:18.701 I/System.out:    name=room_master_table
    2024-04-27 11:00:18.702 I/System.out:    tbl_name=room_master_table
    2024-04-27 11:00:18.702 I/System.out:    rootpage=7
    2024-04-27 11:00:18.702 I/System.out:    sql=CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
    2024-04-27 11:00:18.702 I/System.out: }
    2024-04-27 11:00:18.702 I/System.out: <<<<<
    2024-04-27 11:00:18.702 E/SQLiteLog: (1) no such function: sqlite_compileoption_get
    2024-04-27 11:00:18.702 D/DBINFO: Exception Caught: null
    2024-04-27 11:00:18.702 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@79321e3
    2024-04-27 11:00:18.703 I/System.out: <<<<<
    2024-04-27 11:00:18.703 E/SQLiteLog: (1) no such table: pragma_compile_options
    2024-04-27 11:00:18.703 D/DBINFO: Exception Caught: null
    

    So

    1. the sqlite_compileoption_get is not a known function,
    2. The Cursors retrieved by the PRAGMA is empty according to "No error messages are generated if an unknown pragma is issued. Unknown pragmas are simply ignored." https://www.sqlite.org/pragma.html#pragma_compile_options
    3. The pragma_compile_options table does not exist.

    All very much as you would expect according to:-

    This option is used to omit the compile-time option diagnostics available in SQLite, including the sqlite3_compileoption_used() and sqlite3_compileoption_get() C/C++ functions, the sqlite_compileoption_used() and sqlite_compileoption_get() SQL functions, and the compile_options pragma.