2

I just implemented SQLite database in my project, the app worked perfectly in the old app but after I transfer database files to another app and try to run it, It gave me this error

android.database.sqlite.SQLiteException: no such table: countries (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM countries

Now I tried to run the old app that was working fine, now that is not working too and giving the same error.

I searched a lot about this and tried to solve the errors in these ways but nothing works for me

  • Clearing data, Reinstalling app...
  • Changing version and name of the db...
  • Calling onCreate in onOpen...

and some others like this, But no trick works

This is my entire database helper class (after modification)

class LocationDB(private val myContext: Context) {
    private var dbPath: String? = null
    private var db: SQLiteDatabase? = null
    private var dbHelper: DatabaseHelper

    inner class DatabaseHelper
        (context: Context?) : SQLiteOpenHelper(context, DB_NAME, null, 5) {
        override fun onCreate(db: SQLiteDatabase) {}

        override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
            if(newVersion>oldVersion)
                copyDataBase()
        }

        override fun onOpen(db: SQLiteDatabase?) {
            if (db != null) {
                onCreate(db)
            }
        }
    }

    @Throws(IOException::class)
    fun createDataBase() {
        val dbExist = checkDataBase()
        if (!dbExist) {
            dbHelper.readableDatabase
            try {
                copyDataBase()
            } catch (e: IOException) {
                throw Error("Error copying database")
            }
        }
    }

    private fun checkDataBase(): Boolean {
        var checkDB: SQLiteDatabase? = null
        try {
            val myPath = dbPath + DB_NAME
            checkDB = SQLiteDatabase.openDatabase(
                myPath, null,
                SQLiteDatabase.OPEN_READONLY
            )
        } catch (e: SQLiteException) {
        }
        checkDB?.close()
        return checkDB != null
    }

    @Throws(IOException::class)
    private fun copyDataBase() {
        val myInput = myContext.assets.open(DB_NAME)

        val outFileName = dbPath + DB_NAME

        val myOutput: OutputStream = FileOutputStream(outFileName)

        val buffer = ByteArray(1024)
        var length: Int
        while (myInput.read(buffer).also { length = it } > 0) {
            myOutput.write(buffer, 0, length)
        }

        myOutput.flush()
        myOutput.close()
        myInput.close()
    }

    @Throws(SQLException::class)
    fun openDB(): LocationDB {
        db = dbHelper.writableDatabase
        return this
    }

    fun closeDB() {
        dbHelper.close()
    }

    val countries: Cursor?
        get() {
            val query = "SELECT * FROM countries"
            return db?.rawQuery(query, null)
        }

    fun getStateAsPerCountry(country_id: String): Cursor? {
        val query = "SELECT * FROM states where country_id=$country_id"
        return db?.rawQuery(query, null)
    }

    fun getCitiesAsPerState(state_id: String): Cursor? {
        val query = "SELECT * FROM cities where state_id=$state_id"
        return db?.rawQuery(query, null)
    }

    companion object {
        const val DB_NAME = "Location.db"
    }

    init {
        dbPath = myContext.filesDir.path + myContext.packageName + "/databases/"
        dbHelper = DatabaseHelper(myContext)
    }
}

Edited (10/06/2021)

I see Device File Explorer and I get that the path of the database is /data/data/com.my.package/databases/Location.db by default. And when I debug the app at the error breakpoint, I see that the path is different or we can say that the database helper is getting the database from different path /data/user/0/com.my.package/databases/Location.db which does not exist, So it's clear that without exact path the table will always be null or not created. But the question is why and how can we initialize the right path.

For that, I did this and get the exact path but it is still not working

val countries: Cursor?
        get() {
            db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY) 
            val query = "SELECT * FROM countries"
            return db?.rawQuery(query, null)
        } 

This is a picture of the database

enter image description here

mr. groot
  • 334
  • 4
  • 18

5 Answers5

1

As I understand your question, I don't think that there is any problem with the data helper class you shared. It seems perfect. And I can see there is the country table in Location.db and as you said the database is placed in the right path, but the database doesn't have the table it means it's empty as it should be.

So the problem is with that class where you are using the database since the dummy database is being created but it didn't get the data from your ready-made Location.db, which means it didn't create so for that call

db.createDataBase()

Before calling other functions like countries in onCreate of that class.

Stackoverflower
  • 292
  • 4
  • 17
0

Check your database inspector to know if the table 'countries' really exist.

If not you need to recreate it in your Database Helper.

  • I'm unable to get it in the database inspector. It is displaying as Location.db (Closed), And I don't think that table name can be changed because as I mentioned that the db worked well in the old app. – mr. groot Jun 07 '21 at 07:16
  • you won't be able to access your database if it is closed, it means your database not connected properly, no wonder your table doesn't show up. To fix that maybe you can try to do File -> Invalidate Caches / Restart – frendy wijaya Jun 07 '21 at 07:22
0

Make sure the table name countries has the same spelling as the one in the query.

Update

Try to hardcode your path as

dbPath = "/data/data/com.my.package/databases/"+DB_NAME 
Wowo Ot
  • 1,362
  • 13
  • 21
  • I'm unable to get it in the database inspector. It is displaying as Location.db (Closed), And I don't think that table name can be changed because as I mentioned that the db worked well in the old app. – mr. groot Jun 07 '21 at 07:21
  • Sometimes typos happened. You can try to get to your db location in Android Studio from View > Tool Windows > Device File Explorer to check if the db was copied correctly to the path you specified. – Wowo Ot Jun 07 '21 at 07:34
  • I see that the path is correct as "/data/data/com.my.package/databases/" – mr. groot Jun 07 '21 at 07:43
0

"when I debug the query the variable db returns "/data/user/0/com.my.package/databases/Location.db" while the dbPath is "/data/data/com.my.package/databases/" which means your query checking db under "user" folder not under data folder. that's why you got android.database.sqlite.SQLiteException: no such table: countries .

To check countries table is in your app or not,open View->tool windows->Device file explorer

enter image description here

Under data folder find , "/data/data/com.my.package/databases/Location.db"

Use SQLLiteDatabaseBrowserPortable to check your table under Location db.if Location.db not under databases,you can create new db and table manually using SQLLiteDatabaseBrowserPortable.

Then,change db path to "/data/data/com.my.package/databases/Location.db"

Then run your program.hope will work.

androidLearner
  • 1,654
  • 1
  • 7
  • 13
0

Usually databases are stored under context.getDatabasePath(name). The advantage of this function is that the system makes sure to select the right path instead of hardcoding something.

When your device is connected to Android Studio you can check in your Device File Explorer what files are stored on the device and even access the sandbox of your app where the database can be found. There you can download the file that is in your sandbox and open it locally on your computer.

If the database is correctly configured you could even use the Database Inspector.

When debugging your code with a look at that you will probably find where the database is copied wrong which causes the database to not have the table you are querying.

Christian
  • 4,596
  • 1
  • 26
  • 33