在单线程测试用例中,ALTER TABLE 之前的 SELECT 会隐藏后续 SELECT 中的新列

发布于 2025-01-12 02:34:11 字数 2234 浏览 0 评论 0原文

一步一步

  1. Android Studio Bumblebee ->文件->新->新项目->空活动 ->完成(使用默认值)

  2. 打开app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt并添加以下测试,然后在例如API级别30模拟器上运行它:

    @org.junit.Test
    fun visibility_of_column_after_select_then_alter_then_select_again() {
        val appContext = androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().targetContext

        // Use a fresh DB each time
        val dbPath = appContext.getDatabasePath(java.util.UUID.randomUUID().toString())
        val db = android.database.sqlite.SQLiteDatabase.openDatabase(
            dbPath,
            android.database.sqlite.SQLiteDatabase.OpenParams.Builder()
                .addOpenFlags(android.database.sqlite.SQLiteDatabase.CREATE_IF_NECESSARY)
                .build()
        )

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)
    }

    private fun assertColumnIndex(db: android.database.sqlite.SQLiteDatabase, columnName: String, expectedIndex: Int) {
        val cursor = db.query("some_table", null, null, null, null, null, null)
        org.junit.Assert.assertEquals(expectedIndex, cursor.getColumnIndex(columnName))
        cursor.close()
    }

预期结果

测试通过。

实际结果

在查询 4 ​​之后断言 "new_column" 索引为 1 时,测试失败。它是 -1,也称为“not成立”。这很奇怪,因为我们之前就添加了它。

但是,如果我只执行以下两件事之一,则测试通过:

  • A.// 放在查询 2 前面,即停止发出该 SELECT 查询。我觉得这很奇怪。

  • B..addOpenFlags(SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) 添加到 OpenParams.Builder。这并不奇怪,但并不能让我们更容易理解为什么A.会产生影响。

问题

为什么A.能够通过测试?

Step-by-step

  1. Android Studio Bumblebee -> File -> New -> New Project -> Empty Activity -> Finish (use defaults)

  2. Open app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt and add the following test and then run it on e.g. an API level 30 emulator:

    @org.junit.Test
    fun visibility_of_column_after_select_then_alter_then_select_again() {
        val appContext = androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().targetContext

        // Use a fresh DB each time
        val dbPath = appContext.getDatabasePath(java.util.UUID.randomUUID().toString())
        val db = android.database.sqlite.SQLiteDatabase.openDatabase(
            dbPath,
            android.database.sqlite.SQLiteDatabase.OpenParams.Builder()
                .addOpenFlags(android.database.sqlite.SQLiteDatabase.CREATE_IF_NECESSARY)
                .build()
        )

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)
    }

    private fun assertColumnIndex(db: android.database.sqlite.SQLiteDatabase, columnName: String, expectedIndex: Int) {
        val cursor = db.query("some_table", null, null, null, null, null, null)
        org.junit.Assert.assertEquals(expectedIndex, cursor.getColumnIndex(columnName))
        cursor.close()
    }

Expected result

The test passes.

Actual result

The test fails when asserting on that "new_column" index is 1 after Query 4. It is -1, also known as "not found". Which is strange, because we added it right before.

However, the test PASS if I do just one of the following two things:

  • A. Put // in front of Query 2, i.e. stop issuing that SELECT query. I find this very strange.

  • B. Add .addOpenFlags(SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) to the OpenParams.Builder. This is less strange, but does not make it easier to understand why A. make a difference.

Question

Why does A. make the test pass?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

給妳壹絲溫柔 2025-01-19 02:34:11

或者至少理解为什么在这种情况下需要 WAL。

在 Kotlin 和 Java 中对此进行了测试,结果是相同的,尽管添加了新列(根据架构又名 sqlite_master),但游标似乎不知道而是处于 WAL 模式。

不确定为什么,我怀疑可能是 SQLite API 的问题。

但我想要一个不需要 WAL 的解决方案。

一种解决方案是不使用alter,而是删除表并重新创建它,例如

    db.execSQL("DROP TABLE IF EXISTS some_table")
    db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")

另一种选择是关闭然后重新打开数据库,但是这将相对资源昂贵。

以下用于测试各种场景:-

对于 Java 测试(表​​明 Java 代码也会发生同样的情况):-

class TestJava {

   static void test(Context context) {

      String dbpath = context.getDatabasePath(UUID.randomUUID().toString()).toString();
      SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbpath,null);
      db.execSQL("CREATE TABLE some_table (some_column TEXT)");
      assertColumn(db,"new_column",1);
      db.execSQL("ALTER TABLE some_table ADD new_column TEXT NOT NULL DEFAULT 'x'");
      assertColumn(db,"new_column",1);
   }

   private static void assertColumn(SQLiteDatabase db, String columnName, int expectedIndex) {
      Cursor csr = db.query("some_table",null,null,null,null,null,null);
      int retrievedIndex = csr.getColumnIndex(columnName);
      Log.d("TESTINFO_JAVA","Expected = " + expectedIndex + " Retrieved = " + retrievedIndex);
      csr.close();
   }
}

用于测试的活动:-

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Use a fresh DB each time
        val dbPath = this.getDatabasePath(UUID.randomUUID().toString())
        var db = SQLiteDatabase.openOrCreateDatabase(dbPath, null)
        //db.enableWriteAheadLogging()

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-001")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")
        showSchemaForTable(db,"some_table","TESTINFO-002")
        assertColumnIndex(db, "new_column", 1)
        db.close()
        db = SQLiteDatabase.openDatabase(dbPath.toString(),null,SQLiteDatabase.OPEN_READWRITE)

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)

        // Added to show working equivalent
        db.execSQL("DROP TABLE IF EXISTS some_table")
        db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-003")
        assertColumnIndex(db, "new_column", 1)
        TestJava.test(this)

    }

    private fun assertColumnIndex(db: SQLiteDatabase, columnName: String, expectedIndex: Int) {
        var cursor = db.query("some_table", null, null, null, null, null, null)
        var retrievedIndex = cursor.getColumnIndex(columnName)
        Log.d("TESTINFO", "Expected = ${expectedIndex} RetrievedIndex = ${retrievedIndex} columns in cursor are:-")
        for (cName in cursor.columnNames) {
            Log.d("TESTINFO","\tColumn Name is ${cName}")
        }
        cursor.close()
    }

    @SuppressLint("Range")
    private fun showSchemaForTable(db: SQLiteDatabase, tableName: String, tag: String) {
        var cursor= db.rawQuery("SELECT * FROM sqlite_master WHERE name = '${tableName}'",null)
        while (cursor.moveToNext()) {
            Log.d(tag,"Table is ${tableName} SQL(schema) is ${cursor.getString(cursor.getColumnIndex("sql"))}")
        }
    }
}

日志显示:-

2022-03-05 14:33:17.865 D/TESTINFO-001: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT)
2022-03-05 14:33:17.866 D/TESTINFO: Expected = -1 RetrievedIndex = -1 columns in cursor are:-
2022-03-05 14:33:17.866 D/TESTINFO:     Column Name is some_column

2022-03-05 14:33:17.867 D/TESTINFO-002: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT, new_column TEXT)
2022-03-05 14:33:17.867 D/TESTINFO: Expected = 1 RetrievedIndex = -1 columns in cursor are:-
2022-03-05 14:33:17.867 D/TESTINFO:     Column Name is some_column

2022-03-05 14:33:17.880 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-05 14:33:17.880 D/TESTINFO:     Column Name is some_column
2022-03-05 14:33:17.880 D/TESTINFO:     Column Name is new_column

2022-03-05 14:33:17.889 D/TESTINFO-003: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT, new_column TEXT)
2022-03-05 14:33:17.889 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-05 14:33:17.889 D/TESTINFO:     Column Name is some_column
2022-03-05 14:33:17.889 D/TESTINFO:     Column Name is new_column


2022-03-05 14:33:17.903 D/TESTINFO_JAVA: Expected = 1 Retrieved = -1
2022-03-05 14:33:17.904 D/TESTINFO_JAVA: Expected = 1 Retrieved = -1

其他

进一步测试,使用特定的列名称而不是 *(空),似乎表明有错误的代码。

显然不合适,因为如果指定列不存在,将导致异常。

但是,请考虑一下,下面的

  • 如上所述,实际上并不可用,但这绕过了未找到列的异常,以证明 null 作为查询方法的第二个参数可能无法按预期工作

    • 猜测在打开时提取已知列,也许 WAL 处理的代码更可靠

:-

class MainActivity : AppCompatActivity() {

    var counter = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Use a fresh DB each time
        val dbPath = this.getDatabasePath(UUID.randomUUID().toString())
        var db = SQLiteDatabase.openDatabase(
            dbPath,
            android.database.sqlite.SQLiteDatabase.OpenParams.Builder()
            //.setJournalMode("TRUNCATE")
            .addOpenFlags(android.database.sqlite.SQLiteDatabase.CREATE_IF_NECESSARY)
            .build()
        )
        //db.enableWriteAheadLogging()

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-001")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")
        db.execSQL("INSERT OR IGNORE INTO some_table VALUES ('a','b')")
        //showSchemaForTable(db,"some_table","TESTINFO-002")
        assertColumnIndex(db, "new_column", 1)
        //db.close()
        //db = SQLiteDatabase.openDatabase(dbPath.toString(),null,SQLiteDatabase.OPEN_READWRITE)

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)

        // Added to show working equivalent
        db.execSQL("DROP TABLE IF EXISTS some_table")
        db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")
        //showSchemaForTable(db,"some_table","TESTINFO-003")
        assertColumnIndex(db, "new_column", 1)
    }

    private fun assertColumnIndex(db: SQLiteDatabase, columnName: String, expectedIndex: Int) {
        Log.d("TESTINFO","Invoked assetColumn counter is ${counter}")
        var columns = arrayOf("some_column")
        if (counter > 0) {
            columns = arrayOf("some_column","new_column")
        }
        var cursor = db.query("some_table",  columns, null, null, null, null, null)
        var retrievedIndex = cursor.getColumnIndex(columnName)
        Log.d("TESTINFO", "Expected = ${expectedIndex} RetrievedIndex = ${retrievedIndex} columns in cursor are:-")
        for (cName in cursor.columnNames) {
            Log.d("TESTINFO","\tColumn Name from Cursor is ${cName}")
        }
        counter++
        cursor.close()
    }

    @SuppressLint("Range")
    private fun showSchemaForTable(db: SQLiteDatabase, tableName: String, tag: String) {
        var cursor= db.rawQuery("SELECT * FROM sqlite_master WHERE name = '${tableName}'",null)
        while (cursor.moveToNext()) {
            Log.d(tag,"Table is ${tableName} SQL(schema) is ${cursor.getString(cursor.getColumnIndex("sql"))}")
        }
    }
}

这会导致:-

2022-03-16 07:43:14.531 D/TESTINFO-001: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT)
2022-03-16 07:43:14.531 D/TESTINFO: Invoked assetColumn counter is 0
2022-03-16 07:43:14.531 D/TESTINFO: Expected = -1 RetrievedIndex = -1 columns in cursor are:-
2022-03-16 07:43:14.531 D/TESTINFO:     Column Name from Cursor is some_column

2022-03-16 07:43:14.552 D/TESTINFO: Invoked assetColumn counter is 1
2022-03-16 07:43:14.552 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.552 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.552 D/TESTINFO:     Column Name from Cursor is new_column

2022-03-16 07:43:14.552 D/TESTINFO: Invoked assetColumn counter is 2
2022-03-16 07:43:14.553 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.553 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.553 D/TESTINFO:     Column Name from Cursor is new_column

2022-03-16 07:43:14.577 D/TESTINFO: Invoked assetColumn counter is 3
2022-03-16 07:43:14.578 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.578 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.578 D/TESTINFO:     Column Name from Cursor is new_column

Or at least understand why WAL is needed in this case.

Tested this in Kotlin and Java and the result is the same, although the new column is added (according to the schema aka sqlite_master) the cursor doesn't appear to be aware but is in WAL mode.

Unsure as to why, I suspect it might be the SQLite API.

but I would like a solution that does not require WAL.

One solution would be to not use alter but to drop the table and recreate it e.g.

    db.execSQL("DROP TABLE IF EXISTS some_table")
    db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")

Another alternative is to close and then re-open the database, however this would be relatively resource expensive.

The following was used for testing various scenarios:-

For the Java testing (showing that the same happens with Java code) :-

class TestJava {

   static void test(Context context) {

      String dbpath = context.getDatabasePath(UUID.randomUUID().toString()).toString();
      SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbpath,null);
      db.execSQL("CREATE TABLE some_table (some_column TEXT)");
      assertColumn(db,"new_column",1);
      db.execSQL("ALTER TABLE some_table ADD new_column TEXT NOT NULL DEFAULT 'x'");
      assertColumn(db,"new_column",1);
   }

   private static void assertColumn(SQLiteDatabase db, String columnName, int expectedIndex) {
      Cursor csr = db.query("some_table",null,null,null,null,null,null);
      int retrievedIndex = csr.getColumnIndex(columnName);
      Log.d("TESTINFO_JAVA","Expected = " + expectedIndex + " Retrieved = " + retrievedIndex);
      csr.close();
   }
}

The activity used to test :-

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Use a fresh DB each time
        val dbPath = this.getDatabasePath(UUID.randomUUID().toString())
        var db = SQLiteDatabase.openOrCreateDatabase(dbPath, null)
        //db.enableWriteAheadLogging()

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-001")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")
        showSchemaForTable(db,"some_table","TESTINFO-002")
        assertColumnIndex(db, "new_column", 1)
        db.close()
        db = SQLiteDatabase.openDatabase(dbPath.toString(),null,SQLiteDatabase.OPEN_READWRITE)

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)

        // Added to show working equivalent
        db.execSQL("DROP TABLE IF EXISTS some_table")
        db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-003")
        assertColumnIndex(db, "new_column", 1)
        TestJava.test(this)

    }

    private fun assertColumnIndex(db: SQLiteDatabase, columnName: String, expectedIndex: Int) {
        var cursor = db.query("some_table", null, null, null, null, null, null)
        var retrievedIndex = cursor.getColumnIndex(columnName)
        Log.d("TESTINFO", "Expected = ${expectedIndex} RetrievedIndex = ${retrievedIndex} columns in cursor are:-")
        for (cName in cursor.columnNames) {
            Log.d("TESTINFO","\tColumn Name is ${cName}")
        }
        cursor.close()
    }

    @SuppressLint("Range")
    private fun showSchemaForTable(db: SQLiteDatabase, tableName: String, tag: String) {
        var cursor= db.rawQuery("SELECT * FROM sqlite_master WHERE name = '${tableName}'",null)
        while (cursor.moveToNext()) {
            Log.d(tag,"Table is ${tableName} SQL(schema) is ${cursor.getString(cursor.getColumnIndex("sql"))}")
        }
    }
}

The Log shows :-

2022-03-05 14:33:17.865 D/TESTINFO-001: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT)
2022-03-05 14:33:17.866 D/TESTINFO: Expected = -1 RetrievedIndex = -1 columns in cursor are:-
2022-03-05 14:33:17.866 D/TESTINFO:     Column Name is some_column

2022-03-05 14:33:17.867 D/TESTINFO-002: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT, new_column TEXT)
2022-03-05 14:33:17.867 D/TESTINFO: Expected = 1 RetrievedIndex = -1 columns in cursor are:-
2022-03-05 14:33:17.867 D/TESTINFO:     Column Name is some_column

2022-03-05 14:33:17.880 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-05 14:33:17.880 D/TESTINFO:     Column Name is some_column
2022-03-05 14:33:17.880 D/TESTINFO:     Column Name is new_column

2022-03-05 14:33:17.889 D/TESTINFO-003: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT, new_column TEXT)
2022-03-05 14:33:17.889 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-05 14:33:17.889 D/TESTINFO:     Column Name is some_column
2022-03-05 14:33:17.889 D/TESTINFO:     Column Name is new_column


2022-03-05 14:33:17.903 D/TESTINFO_JAVA: Expected = 1 Retrieved = -1
2022-03-05 14:33:17.904 D/TESTINFO_JAVA: Expected = 1 Retrieved = -1

Additional

Further testing, using specific column names rather than * (null), seems to indicate buggy code.

Obviously not suitable, as specifying the column if non-existent, would result in an exception.

However, consider, the following

  • as said not really usable but this circumvents the column not found exception to prove the point that null as the 2nd parameter of the query method perhaps doesn't work as intended

    • at a guess extracting the known columns at open and perhaps that the code for WAL handling is a little more solid

:-

class MainActivity : AppCompatActivity() {

    var counter = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Use a fresh DB each time
        val dbPath = this.getDatabasePath(UUID.randomUUID().toString())
        var db = SQLiteDatabase.openDatabase(
            dbPath,
            android.database.sqlite.SQLiteDatabase.OpenParams.Builder()
            //.setJournalMode("TRUNCATE")
            .addOpenFlags(android.database.sqlite.SQLiteDatabase.CREATE_IF_NECESSARY)
            .build()
        )
        //db.enableWriteAheadLogging()

        // Query 1: CREATE TABLE
        db.execSQL("CREATE TABLE some_table (some_column TEXT)")
        showSchemaForTable(db,"some_table","TESTINFO-001")

        // Query 2: SELECT all columns (to assert on index of new_column)
        assertColumnIndex(db, "new_column", -1)

        // Query 3: ALTER TABLE to add column
        db.execSQL("ALTER TABLE some_table ADD new_column TEXT")
        db.execSQL("INSERT OR IGNORE INTO some_table VALUES ('a','b')")
        //showSchemaForTable(db,"some_table","TESTINFO-002")
        assertColumnIndex(db, "new_column", 1)
        //db.close()
        //db = SQLiteDatabase.openDatabase(dbPath.toString(),null,SQLiteDatabase.OPEN_READWRITE)

        // Query 4: SELECT all columns again (to assert on index of new_column)
        assertColumnIndex(db, "new_column", 1)

        // Added to show working equivalent
        db.execSQL("DROP TABLE IF EXISTS some_table")
        db.execSQL("CREATE TABLE IF NOT EXISTS some_table (some_column TEXT, new_column TEXT)")
        //showSchemaForTable(db,"some_table","TESTINFO-003")
        assertColumnIndex(db, "new_column", 1)
    }

    private fun assertColumnIndex(db: SQLiteDatabase, columnName: String, expectedIndex: Int) {
        Log.d("TESTINFO","Invoked assetColumn counter is ${counter}")
        var columns = arrayOf("some_column")
        if (counter > 0) {
            columns = arrayOf("some_column","new_column")
        }
        var cursor = db.query("some_table",  columns, null, null, null, null, null)
        var retrievedIndex = cursor.getColumnIndex(columnName)
        Log.d("TESTINFO", "Expected = ${expectedIndex} RetrievedIndex = ${retrievedIndex} columns in cursor are:-")
        for (cName in cursor.columnNames) {
            Log.d("TESTINFO","\tColumn Name from Cursor is ${cName}")
        }
        counter++
        cursor.close()
    }

    @SuppressLint("Range")
    private fun showSchemaForTable(db: SQLiteDatabase, tableName: String, tag: String) {
        var cursor= db.rawQuery("SELECT * FROM sqlite_master WHERE name = '${tableName}'",null)
        while (cursor.moveToNext()) {
            Log.d(tag,"Table is ${tableName} SQL(schema) is ${cursor.getString(cursor.getColumnIndex("sql"))}")
        }
    }
}

This results in :-

2022-03-16 07:43:14.531 D/TESTINFO-001: Table is some_table SQL(schema) is CREATE TABLE some_table (some_column TEXT)
2022-03-16 07:43:14.531 D/TESTINFO: Invoked assetColumn counter is 0
2022-03-16 07:43:14.531 D/TESTINFO: Expected = -1 RetrievedIndex = -1 columns in cursor are:-
2022-03-16 07:43:14.531 D/TESTINFO:     Column Name from Cursor is some_column

2022-03-16 07:43:14.552 D/TESTINFO: Invoked assetColumn counter is 1
2022-03-16 07:43:14.552 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.552 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.552 D/TESTINFO:     Column Name from Cursor is new_column

2022-03-16 07:43:14.552 D/TESTINFO: Invoked assetColumn counter is 2
2022-03-16 07:43:14.553 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.553 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.553 D/TESTINFO:     Column Name from Cursor is new_column

2022-03-16 07:43:14.577 D/TESTINFO: Invoked assetColumn counter is 3
2022-03-16 07:43:14.578 D/TESTINFO: Expected = 1 RetrievedIndex = 1 columns in cursor are:-
2022-03-16 07:43:14.578 D/TESTINFO:     Column Name from Cursor is some_column
2022-03-16 07:43:14.578 D/TESTINFO:     Column Name from Cursor is new_column
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文