Использование триггеров SQLite на Android возвращает ошибку - PullRequest
2 голосов
/ 27 апреля 2019

Я новичок в SQLite, я пытаюсь создать приложение, в котором пользователь может создавать задачи и прикреплять к ним напоминания. Я использую SQLite базу данных для сохранения этих предметов. Все работает отлично, теперь я хочу реализовать функцию полнотекстового поиска, я прочитал SQLite документацию, что использование FTS4 VIRTUAL TABLE намного лучше обычного.

  • поэтому для синхронизации виртуальной таблицы мне пришлось использовать триггеры. но после вызова execSQL("//*Trigger code*//")

вот мои триггеры (использующие их в том же порядке, что и в документации) :

object SQLiteTriggerUtils {

    fun getBeforeDeleteTrigger(mainTable : String,
                               ftsTable : String,
                               rowId : Int?) : String {

        return "CREATE TRIGGER table_bd" +
                " BEFORE DELETE ON $mainTable" +
                " BEGIN DELETE FROM $ftsTable" +
                " WHERE docid=$rowId END;"
    }

    fun getBeforeUpdateTrigger(mainTable: String,
                               ftsTable: String,
                               rowId: Int?) : String {

        return "CREATE TRIGGER table_bu" +
                " BEFORE UPDATE ON $mainTable" +
                " BEGIN DELETE FROM $ftsTable" +
                " WHERE docid=$rowId END;"
    }

    fun getAfterUpdateTrigger(
        mainTable: String,
        ftsTable: String,
        rowId: Int?,
        updatedField: String,
        updatedValue: String?
    ) : String {

        return "CREATE TRIGGER table_au" +
                " AFTER UPDATE ON $mainTable" +
                " BEGIN INSERT INTO $ftsTable(docid, $updatedField)" +
                " VALUES($rowId, $updatedValue) END;"
    }

    fun getAfterInsertTrigger(
        mainTable: String,
        ftsTable: String,
        rowId: Int?,
        updatedField: String,
        updatedValue: String?
    ) : String {

        return "CREATE TRIGGER table_ai" +
                " AFTER INSERT ON $mainTable" +
                " BEGIN INSERT INTO $ftsTable(docid, $updatedField)" +
                " VALUES($rowId, $updatedValue) END;"
    }
}

вот моя база данных по методу onCreate () :

override fun onCreate(db: SQLiteDatabase) {
        val CREATION_TABLE = ("CREATE TABLE $TABLE_NAME ( "
                + "$KEY_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "$KEY_LABEL TEXT, "
                + "$KEY_DESCRIPTION TEXT, "
                + "$KEY_IMPORTANCE INTEGER,"
                + "$KEY_LOGO INTEGER,"
                + "$KEY_TO_DO_DATE TEXT,"
                + "$KEY_CREATION_DATE TEXT)")
        val FTS_CREATION_TABLE = ("CREATE VIRTUAL TABLE $FTS_TABLE_NAME USING fts4 (content='$TABLE_NAME', $KEY_LABEL)")
        db.execSQL(CREATION_TABLE)
        db.execSQL(FTS_CREATION_TABLE)
    } 

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        db.execSQL("DROP TABLE IF EXISTS $FTS_TABLE_NAME")
        onCreate(db)
    }

пример вызова триггеров для метода onDeleteItem () :

override fun deleteItem(itemId: Int): Boolean {
        var success : Boolean
        writableDatabase.apply {
            execSQL(SQLiteTriggerUtils.getBeforeDeleteTrigger(TABLE_NAME, FTS_TABLE_NAME, itemId))
            success = delete(TABLE_NAME, "id = ?", arrayOf(itemId.toString())) > 0
            close()
        }
        return success
    }

возвращенная ошибка :

android.database.sqlite.SQLiteException: near "END": syntax error (Sqlite code 1): , while compiling: CREATE TRIGGER table_bd BEFORE DELETE ON todo_tasks BEGIN DELETE FROM fts_todo_tasks WHERE docid=1 END;, (OS error - 2:No such file or directory)

1 Ответ

2 голосов
/ 28 апреля 2019

Я думаю, что ваши проблемы после исправления синтаксической ошибки следуют за триггерными действиями, которые закодированы между BEGIN и END с точкой с запятой согласно: -

enter image description here

Возможно, вы пытались добавить триггеры до того, как узнали значение (возможно, это не зависит от кода).

Это триггеробъект, такой как представление, таблица, индекс и т. д., который является частью схемы и поэтому требует уникального имени.Так что CREATE TRIGGER the_trigger_name ...... требует, чтобы the_trigger_name было уникальным.Похоже, что вы, возможно, пытаетесь создать один и тот же триггер каждый раз, когда действие, которое будет вызывать триггер, будет готово к действию, а затем завершится ошибкой, поскольку триггер уже существует.этот существующий триггер затем будет использован.

Поэтому, возможно, вы захотите DROP TRIGGER the_trigger_name перед созданием триггера.

Однако!

Сказать, что ожидаемое использование триггероввыполнить подобное действие автоматически, когда событие (UPDATE, DELETE или INSERT) происходит (фактически непосредственно перед или после).Таким образом, триггер имеет доступ к столбцам строки, в результате чего запускается триггер (действие триггера).

Если инициирующим действием является INSERT, то на столбцы вставляемой строки можно ссылаться с помощью new.столбец и используется в инициируемом действии (действия, указанные между BEGIN и END).

Если инициирующим действием является DELETE, то old.column может использоваться для ссылки на столбцы удаляемой строки.

Если инициирующим действием является ОБНОВЛЕНИЕ, то можно ссылаться как на new.column, так и на old.column.

  • , где .column заменяется соответствующим столбцом.

Таким образом, когда документация гласит: -

Вместо того, чтобы записывать отдельно в полнотекстовый индекс и таблицу содержимого, некоторые пользователи могут захотеть использовать триггеры базы данных дляподдерживать полнотекстовый индекс в актуальном состоянии по отношению к набору документов, хранящихся в таблице содержимого.Например, используя таблицы из предыдущих примеров:

CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 BEGIN
  DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_bd BEFORE DELETE ON t2 BEGIN
  DELETE FROM t3 WHERE docid=old.rowid;
END;

CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN
  INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN
  INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;

Вы увидите, что он использует old.docid и new.rowid

Таким образом, old.docid будет docid для удаляемой строки, а new.rowid будет строкой строки, вставляемой в $ TABLE_NAME .Таким образом, каждый триггер должен быть определен только один раз, поскольку он является общим.

Таким образом, я полагаю, что вы можете использовать: -

val TRG_BD = "trigger_bd" //<<<<<<<<<< ADDED >>>>>>>>>>
val TRG_BU = "trigger_bu" //<<<<<<<<<< ADDED >>>>>>>>>>
val TRG_AU = "trigger_au" //<<<<<<<<<< ADDED >>>>>>>>>>
val TRG_AI = "trigger_ai" //<<<<<<<<<< ADDED >>>>>>>>>>

override fun onCreate(db: SQLiteDatabase) {
    val CREATION_TABLE = ("CREATE TABLE $TABLE_NAME ( "
            + "$KEY_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
            + "$KEY_LABEL TEXT, "
            + "$KEY_DESCRIPTION TEXT, "
            + "$KEY_IMPORTANCE INTEGER,"
            + "$KEY_LOGO INTEGER,"
            + "$KEY_TO_DO_DATE TEXT,"
            + "$KEY_CREATION_DATE TEXT)")
    val FTS_CREATION_TABLE = ("CREATE VIRTUAL TABLE $FTS_TABLE_NAME USING fts4 (content='$TABLE_NAME', $KEY_LABEL)")

    //<<<<<<<<<< ADDED FOLLOWING LINES  >>>>>>>>
    val BD_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_BD " +
            "BEFORE DELETE ON $TABLE_NAME " +
            "BEGIN " +
            "DELETE FROM $FTS_TABLE_NAME " +
            "WHERE docid=old.rowid; " +
            "END;")
    val BU_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_BU " +
            "BEFORE UPDATE ON $TABLE_NAME " +
            "BEGIN " +
            "DELETE FROM $FTS_TABLE_NAME " +
            "WHERE docid=old.rowid; " +
            "END;")
    val AU_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_AU " +
            "AFTER UPDATE ON $TABLE_NAME " +
            "BEGIN " +
            "INSERT INTO $FTS_TABLE_NAME (docid, $KEY_LABEL) VALUES(new.$KEY_ID,new.$KEY_LABEL); " + //<<<<<<<< not sure $KEY_LABEL is correct column
            "END;")
    val AI_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_AI " +
            "AFTER INSERT ON $TABLE_NAME " +
            "BEGIN " +
            "INSERT INTO $FTS_TABLE_NAME (docid, $KEY_LABEL) VALUES(new.$KEY_ID,new.$KEY_LABEL); " +
            "END;")
    //<<<<<<<<<< END OF ADDED LINES >>>>>>>>


    db.execSQL(CREATION_TABLE)
    db.execSQL(FTS_CREATION_TABLE)
    db.execSQL(BD_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
    db.execSQL(BU_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
    db.execSQL(AU_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
    db.execSQL(AI_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
    db.execSQL("DROP TABLE IF EXISTS $FTS_TABLE_NAME")
    db.execSQL("DROP TRIGGER IF EXISTS $TRG_BD") //<<<<<<<<<< ADDDED >>>>>>>>
    db.execSQL("DROP TRIGGER IF EXISTS $TRG_BU") //<<<<<<<<<< ADDDED >>>>>>>>
    db.execSQL("DROP TRIGGER IF EXISTS $TRG_AU") //<<<<<<<<<< ADDDED >>>>>>>>
    db.execSQL("DROP TRIGGER If EXISTS $TRG_AI") //<<<<<<<<<< ADDDED >>>>>>>>
    onCreate(db)
}

Вышеприведенное заменит (т.е.в таком случае следующее не потребуется): -

object SQLiteTriggerUtils {

    fun getBeforeDeleteTrigger(mainTable : String,
                               ftsTable : String,
                               rowId : Int?) : String {

        return "CREATE TRIGGER table_bd" +
                " BEFORE DELETE ON $mainTable" +
                " BEGIN DELETE FROM $ftsTable" +
                " WHERE docid=$rowId END;"
    }

    fun getBeforeUpdateTrigger(mainTable: String,
                               ftsTable: String,
                               rowId: Int?) : String {

        return "CREATE TRIGGER table_bu" +
                " BEFORE UPDATE ON $mainTable" +
                " BEGIN DELETE FROM $ftsTable" +
                " WHERE docid=$rowId END;"
    }

    fun getAfterUpdateTrigger(
        mainTable: String,
        ftsTable: String,
        rowId: Int?,
        updatedField: String,
        updatedValue: String?
    ) : String {

        return "CREATE TRIGGER table_au" +
                " AFTER UPDATE ON $mainTable" +
                " BEGIN INSERT INTO $ftsTable(docid, $updatedField)" +
                " VALUES($rowId, $updatedValue) END;"
    }

    fun getAfterInsertTrigger(
        mainTable: String,
        ftsTable: String,
        rowId: Int?,
        updatedField: String,
        updatedValue: String?
    ) : String {

        return "CREATE TRIGGER table_ai" +
                " AFTER INSERT ON $mainTable" +
                " BEGIN INSERT INTO $ftsTable(docid, $updatedField)" +
                " VALUES($rowId, $updatedValue) END;"
    }
}

и, кроме того, поскольку TRIGGERS запускаются автоматически,

override fun deleteItem(itemId: Int): Boolean {
        var success : Boolean
        writableDatabase.apply {
            execSQL(SQLiteTriggerUtils.getBeforeDeleteTrigger(TABLE_NAME, FTS_TABLE_NAME, itemId))
            success = delete(TABLE_NAME, "id = ?", arrayOf(itemId.toString())) > 0
            close()
        }
        return success
    }

можно заменить на (ианалогично для остальных): -

override fun deleteItem(itemId: Int): Boolean {
        var success : Boolean
        writableDatabase.apply {
            success = delete(TABLE_NAME, "id = ?", arrayOf(itemId.toString())) > 0
            close()
        }
        return success
    }

ПРИМЕЧАНИЕ Выше приведен принципиальный код , он не был проверен или запущен.Как таковой он может содержать ошибки.

  • Я бы также предложил, чтобы в именах триггеров вместо использования au (после обновления) использовалось больше описательных имен и, следовательно, соглашение об именах не было таким ограничительным (например, скажем,Вы хотели использовать другой после триггера обновления?).

Рабочий пример

Ниже приведен рабочий пример, демонстрирующий триггеры (обратите внимание на небольшой опыт Kotlin, поэтому кодможет быть не лучшим)

DatabaseHelper.kt

val DB_VERSION = 1;
val DB_NAME = "mydb"

public class DatabaseHelper(context: Context?) :

    SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {

    val TABLE_NAME = "mytable"
    val FTS_TABLE_NAME = "myftstable"
    val TRG_BD = "trigger_bd"
    val TRG_BU = "trigger_bu"
    val TRG_AU = "trigger_au"
    val TRG_AI = "trigger_ai"
    val KEY_ID = "id";
    val KEY_LABEL = "label"
    val KEY_DESCRIPTION = "desctription"
    val KEY_IMPORTANCE = "importance";
    val KEY_LOGO = "logo";
    val KEY_TO_DO_DATE = "todo_date"
    val KEY_CREATION_DATE = "creation_date"



    override fun onCreate(db: SQLiteDatabase) {
        val CREATION_TABLE = ("CREATE TABLE $TABLE_NAME ( "
                + "$KEY_ID INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "$KEY_LABEL TEXT, "
                + "$KEY_DESCRIPTION TEXT, "
                + "$KEY_IMPORTANCE INTEGER,"
                + "$KEY_LOGO INTEGER,"
                + "$KEY_TO_DO_DATE TEXT,"
                + "$KEY_CREATION_DATE TEXT)")
        val FTS_CREATION_TABLE = ("CREATE VIRTUAL TABLE $FTS_TABLE_NAME USING fts4 (content='$TABLE_NAME', $KEY_LABEL)")

        //<<<<<<<<<< ADDED FOLLOWING LINES  >>>>>>>>
        val BD_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_BD " +
                "BEFORE DELETE ON $TABLE_NAME " +
                "BEGIN " +
                "DELETE FROM $FTS_TABLE_NAME " +
                "WHERE docid=old.$KEY_ID; " +
                "END;")
        val BU_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_BU " +
                "BEFORE UPDATE ON $TABLE_NAME " +
                "BEGIN " +
                "DELETE FROM $FTS_TABLE_NAME " +
                "WHERE docid=old.$KEY_ID; " +
                "END;")
        val AU_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_AU " +
                "AFTER UPDATE ON $TABLE_NAME " +
                "BEGIN " +
                "INSERT INTO $FTS_TABLE_NAME (docid, $KEY_LABEL) VALUES(new.$KEY_ID,new.$KEY_LABEL); " + //<<<<<<<< not sure $KEY_LABEL is correct column
                "END;")
        val AI_CREATION_TRIGGER = ("CREATE TRIGGER IF NOT EXISTS $TRG_AI " +
                "AFTER INSERT ON $TABLE_NAME " +
                "BEGIN " +
                "INSERT INTO $FTS_TABLE_NAME (docid, $KEY_LABEL) VALUES(new.$KEY_ID,new.$KEY_LABEL); " +
                "END;")
        db.execSQL(CREATION_TABLE)
        db.execSQL(FTS_CREATION_TABLE)
        db.execSQL(BD_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
        db.execSQL(BU_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
        db.execSQL(AU_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
        db.execSQL(AI_CREATION_TRIGGER) //<<<<<<<<<< ADDED >>>>>>>>>>
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        db.execSQL("DROP TABLE IF EXISTS $FTS_TABLE_NAME")
        db.execSQL("DROP TRIGGER IF EXISTS $TRG_BD") //<<<<<<<<<< ADDDED >>>>>>>>
        db.execSQL("DROP TRIGGER IF EXISTS $TRG_BU") //<<<<<<<<<< ADDDED >>>>>>>>
        db.execSQL("DROP TRIGGER IF EXISTS $TRG_AU") //<<<<<<<<<< ADDDED >>>>>>>>
        db.execSQL("DROP TRIGGER If EXISTS $TRG_AI") //<<<<<<<<<< ADDDED >>>>>>>>
        onCreate(db)
    }

    fun insert(label: String, description: String, importance: Int, tododate: String, creationdate: String ) {

        val cv = ContentValues()
        cv.put(KEY_LABEL,label)
        cv.put(KEY_DESCRIPTION,description)
        cv.put(KEY_IMPORTANCE,importance)
        cv.put(KEY_LOGO,0)
        cv.put(KEY_TO_DO_DATE,tododate)
        cv.put(KEY_CREATION_DATE,creationdate)

        val db = this.writableDatabase
        val inserted = db.insert(TABLE_NAME, null, cv )
        Log.d("INSERT","INSERT result in an id of " + inserted + ".")
    }

    fun update(id: Long, label: String) {
        val cv = ContentValues()
        cv.put(KEY_LABEL,label)

        val db = this.writableDatabase
        val updated = db.update(TABLE_NAME,cv,"$KEY_ID =" + id,null)
        Log.d("UPDATED","UPDATE resulted in " + updated + " rows being updated.")
    }

    fun delete(id: Long) {
        val whereclause = "$KEY_ID=" + id

        val db = this.writableDatabase
        val deleted = db.delete(TABLE_NAME,whereclause,null)
        Log.d("DELETED","DELETE resulted in " + deleted + " rows being deleted.")
    }

    fun logtables() {
        val db = this.writableDatabase
        val csr1 = db.query(TABLE_NAME, null, null, null, null, null, null)
        dumpCursor(csr1)
        val csr2 = db.query(FTS_TABLE_NAME,null,null,null,null,null,null)
        dumpCursor(csr2)
        csr1.close()
        csr2.close()
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

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

        val dbhelper = DatabaseHelper(this)
        dbhelper.insert("TEST001","Just Testing",10,"2019-01-01","2019-01-01")
        dbhelper.logtables()
        dbhelper.update(1,"001TEST")
        dbhelper.logtables()
        dbhelper.delete(1)
        dbhelper.logtables()
    }
}

Результат (журнал)

04-28 14:35:21.002 17810-17810/s.e.myapplication D/INSERT: INSERT result in an id of 1.
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@11697ce
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: 0 {
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    id=1
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    label=TEST001
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    desctription=Just Testing
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    importance=10
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    logo=0
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    todo_date=2019-01-01
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    creation_date=2019-01-01
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: }
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: <<<<<
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@3396ef
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out: 0 {
04-28 14:35:21.002 17810-17810/s.e.myapplication I/System.out:    label=TEST001
04-28 14:35:21.003 17810-17810/s.e.myapplication I/System.out: }
04-28 14:35:21.003 17810-17810/s.e.myapplication I/System.out: <<<<<

то есть в FTS была вставлена ​​строка для TEST001

04-28 14:35:21.007 17810-17810/s.e.myapplication D/UPDATED: UPDATE resulted in 1 rows being updated.
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@9ce45fc
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out: 0 {
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    id=1
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    label=001TEST
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    desctription=Just Testing
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    importance=10
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    logo=0
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    todo_date=2019-01-01
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out:    creation_date=2019-01-01
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out: }
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out: <<<<<
04-28 14:35:21.007 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@30ec485
04-28 14:35:21.008 17810-17810/s.e.myapplication I/System.out: 0 {
04-28 14:35:21.008 17810-17810/s.e.myapplication I/System.out:    label=001TEST
04-28 14:35:21.008 17810-17810/s.e.myapplication I/System.out: }
04-28 14:35:21.008 17810-17810/s.e.myapplication I/System.out: <<<<<

т.е. таблица FTS была обновлена ​​для отражения того, что TEST001 изменяется на 001TEST

04-28 14:35:21.011 17810-17810/s.e.myapplication D/DELETED: DELETE resulted in 1 rows being deleted.
04-28 14:35:21.011 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@10862da
04-28 14:35:21.011 17810-17810/s.e.myapplication I/System.out: <<<<<
04-28 14:35:21.011 17810-17810/s.e.myapplication I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@d4cb30b
04-28 14:35:21.011 17810-17810/s.e.myapplication I/System.out: <<<<<

после удаления из таблицы non-fts оба пусты

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...