no such table exception SQLite - android

My code is now as follows:
Main app java:
String TAG = "DATABASES";
try {
String destPath = "/data/data/" + getPackageName()
+ "/databases/data.db";
File f = new File(destPath);
if(!f.exists()){
Log.v(TAG,"Dest DB doesn't exist");
InputStream in = getAssets().open("airports.db");
OutputStream out = new FileOutputStream(destPath);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
} else {
Log.v(TAG,"File exists: " + destPath);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
Log.v(TAG,"ioexeption");
e.printStackTrace();
}
DBManager dbManager = new DBManager(this);
Log.v(TAG,"Database is there with version: "+dbManager.getReadableDatabase().getVersion());
//String sql = "select * from airports where IATA='GRO' ";
String sql = "select count(*) from airports";
SQLiteDatabase db = dbManager.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, null);
Log.v(TAG,"Query Result:"+cursor);
cursor.close();
db.close();
dbManager.close();
My DBManager.java:
package com.jammo.mywidget4;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DBManager extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String TAG = "DATABASES";
public DBManager(Context context) {
super(context, "data.db", null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.v(TAG,"On create Called:"+db.getPath());
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Now the execution runs ok in the main.java on initiation of "db", however fails on the next line where it tries to execute rawQuery()
FYI "select count(*) from airports" run on my Sqlite DB Manager GUI returns 1650 rows.
Error log is saying :
03-04 21:54:24.200: E/AndroidRuntime(11513): FATAL EXCEPTION: main
03-04 21:54:24.200: E/AndroidRuntime(11513): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jammo.mywidget4/com.jammo.mywidget4.SectorInfo}: android.database.sqlite.SQLiteException: no such table: airports: , while compiling: select count(*) from airports
Local /assets/airports.db "seems" to be being detected and copied to /data/data/mypackage/databases/data.db as "file is found"
Many thanks
J

Try it without using your DBManager class.
Comment out this line...
DBManager dbManager = new DBManager(this);
...then open the database explicitly by replacing this line...
SQLiteDatabase db = dbManager.getReadableDatabase();
...with...
SQLiteDatabase db = SQLiteDatabase.openDatabase(destPath, null, SQLiteDatabase.OPEN_READONLY);
Then clear the app data so the database is re-copied from your assets directory.
EDIT: Even though my suggestion worked, it's actually just a workaround and the root of your problem was this...
String destPath = "/data/data/" + getPackageName() + "/databases/data.db";
You should avoid using hard-coded paths with Android - they may work fine for many devices but there is no guarantee they'll work with all devices or even with all versions of Android.
The problem was you were creating / copying your database to that path but the DBManager class was presumably creating an empty database located somewhere on a different path in the file-system.
To fix this for all devices and Android versions, before copying the database, I would use...
SQLiteDatabase.openOrCreateDatabase("data.db", null)
...to create a 'dummy' (empty) database. Then I'd call...
getDatabasePath("data.db")
...to get the absolute path to data.db. You can then overwrite that database during the copy operation and from then on you can use a class which extends SQLiteOpenHelper and it will find the correct database.

Related

Unusual behaviour in app using existing database

I'm experimenting with using an existing database that is provided to the app in the Assets folder.
When I run the app for the very first time, I get an NullPointerException on an InputSteam object.
If I run the app a second time, then the input stream is not null but this time, I get an SQLiteException: no such table.
Very unusual, I'm wondering if anyone could help find the cause.
In this project, I created a simple SQLite database file and stored it in the Assets folder. It is called Customers.db and contains one table called CustomerList. The table columns are ID (integer primary key), CustomerName and Country.
In the DatabaseHelper object, the method loadDatabase() loads the database from the assets folder into the phone's internal memory.
DatabaseHelper method getRecords() returns an Array of Customer objects and these are the fields of these customer objects are listed in a RecyclerView in the MainActivity. To simply the experiment, as a first step, the getRecords() method return all the rows of the table.
When run for the first time the following exception is reported:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mo.useexistingdatabasedemo/com.mo.useexistingdatabasedemo.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.read(byte[], int, int)' on a null object reference
And the second time it's run, the input stream seems to be no longer null, but instead an sqliteexception is reported:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mo.useexistingdatabasedemo/com.mo.useexistingdatabasedemo.MainActivity}: android.database.sqlite.SQLiteException: no such table: CustomerList (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM CustomerList
In ,my project class DatabaseHelper is defined as follows (and its methods are called from the MainActivity).
package com.mo.useexistingdatabasedemo;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.Buffer;
import java.util.ArrayList;
public class DatabaseHelper extends SQLiteOpenHelper {
public static ArrayList<Customer> arrayList = new ArrayList<>();
public static final String DATABASE_NAME = "Customers.db";
public static final String TABLE_NAME = "CustomerList";
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_DIRECTORY_PATH = "data/data/com.mo" +
".useexistingdatabasedemo/databases";
public static final String DATABASE_FILE_PATH = DATABASE_DIRECTORY_PATH + DATABASE_NAME;
Context context;
InputStream inputStream;
OutputStream outputStream;
Buffer buffer;
public static final String SELECT_ALL_TABLE = "SELECT * FROM " + TABLE_NAME;
public DatabaseHelper(#Nullable Context context) {
super(context, DATABASE_NAME, null, 2);
this.context = context;
}
public void loadDatabase() {
String path = DATABASE_DIRECTORY_PATH + DATABASE_NAME;
File dbFile = new File(path); // the descriptor of a file in internal memory to which
// we will write the db in the assets folder.
// if the database isn't already in internal memory, copy it over from assets.
if (!dbFile.exists()) {
try {
inputStream = context.getAssets().open(DATABASE_NAME);
} catch (IOException e) {
Log.e("IOException input stream: ",
"Exception opening input stream " + e.getMessage());
}
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(path);
} catch (FileNotFoundException e) {
Log.e("IOException, output stream: ",
"Exception creating output stream " + e.getMessage());
}
// create a buffer of 1024 bytes length
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer, 0, 1024)) > 0)
outputStream.write(buffer, 0, len);
outputStream.flush();
inputStream.close();
} catch (IOException e) {
Log.e("IOException", "Exception occurred in while block" + e.getMessage());
}
}
Log.i("Load database", "The method public loadDatabase() executed succesffully");
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public ArrayList getRecords() {
SQLiteDatabase database = getWritableDatabase();
Log.i("The attached database is :", database.getAttachedDbs().toString());
Cursor cursor = database.rawQuery("SELECT * FROM " + TABLE_NAME, null);
while (cursor.moveToNext()) {
Customer customer = new Customer();
customer.customerName = cursor.getColumnName(1).toString();
customer.country = cursor.getColumnName(2).toString();
arrayList.add(customer);
}
return arrayList;
}
}
Unusual behaviour in app using existing database
The Issue(s)
Not at all unusual. You are not copying the database to it's expected location, which is data/data/your_package/databases (directory) However no need to know or even code that (see later).
First run and the copy fails BUT the file is created.
Second run as the file exists, no attempt is made to copy. So theSQLiteOpenHelper subclass can't find the database, as it's not in the expected location, so it invokes the onCreate method and creates the database without any tables and hence the table not found.
The Fix
I would suggest NOT hard coding the path but getting the path via the Context's getDatabasePath method. e.g.
String dbpath = context.getDatabasePath(name).getPath();
or as a File :-
File db = context.getDatabasePath(name);
After acquiring I suggest checking if the parent directory exists and if not then issuing a mkdirs so that the databases folder is created if it doesn't exist (for older API's it will not and it's non existence prevents the copy working but with the file existing, I believe I saw that later versions create the directory). e.g. something like :-
File db = context.getDatabasePath(name);
if (!db.getParentFile().exists()) db.mkdirs();
String dbpath = db.getPath(); // may not be needed as the File object is what is then required
Here's is an example of a pretty bulletproof SQLiteOpenHelper subclass that will copy a pre-existing database.

Cause by: android.database.sqlite.SQLiteException no such table: Category (code 1 SQLITE_ERROR): , while compiling: SELECT *FROM Category WHERE tag =?

In my app i used sqlite db file for getting some data. It works fine for most of the users but some of them getting crash Cause by: android.database.sqlite.SQLiteException: no such table: getCtgList (code 1): ,
while compiling: "SELECT *FROM Category WHERE tag =?", new String[]{string}"
Below is my SQLite DBHelper class to create and copy database. in asster/font.db has a Category table . after copying this table some of device missing this table. I searched a lot to fix this error but didn't find any solution. and I'm getting trending issues for app crashing on google play store. Please help me to fix this error.
Code:
package com.softtechbd.nickname_finder.Database;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
public class DBHelper extends SQLiteOpenHelper {
public static final String location = "/data/data/com.com.softtechbd.stylishnicknamegenerator/databases";
private static final String DB_Name = "font_data.db";
private static final int DB_Ver = 2;
private Context mContext;
private SQLiteDatabase database;
private Object String;
public DBHelper(#Nullable Context context) {
super(context, DB_Name, null, DB_Ver);
this.mContext= context;
initialize();
}
private void initialize() {
if (databaseExists() ){
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(mContext);
int dbVersion = prefs.getInt("db_ver", 1);
if (DB_Ver != dbVersion) {
File dbFile = mContext.getDatabasePath(DB_Name);
if (!dbFile.delete()) {
Log.w("dbexists", "Unable to update database");
}
}
}
if (!databaseExists()){
this.getReadableDatabase();
try {
copyDatabase();
}catch (Exception e){
e.printStackTrace();
}
copyDatabase();
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
}
}
private void copyDatabase(){
try {
InputStream inputStream = mContext.getAssets().open(DB_Name);
FileOutputStream fileOutputStream = new FileOutputStream(
"/data/data/"+mContext.getPackageName()+"/databases/"+DB_Name);
byte[]arrby = new byte[1024];
do {
int n;
if((n=inputStream.read(arrby)) <=0 ){
fileOutputStream.flush();
fileOutputStream.close();
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences((mContext)).edit();
editor.putInt("db_ver",DB_Ver);
editor.apply();
// Toast.makeText(mContext, "SQLite DB copied", Toast.LENGTH_SHORT).show();
return;
}
fileOutputStream.write(arrby,0,n);
}while (true);
}catch (Exception e){
e.printStackTrace();
}
}
private void closeDatabase(){
SQLiteDatabase sqLiteDatabase = this.database;
if(sqLiteDatabase!= null){
sqLiteDatabase.close();
}
}
private boolean databaseExists() {
File dbFile = mContext.getDatabasePath(DB_Name);
return dbFile.exists();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void openDatabase(){
String string = this.mContext.getDatabasePath(DB_Name).getPath();
SQLiteDatabase sqLiteDatabase = this.database;
if(sqLiteDatabase!=null && sqLiteDatabase.isOpen()){
return;
}
this.database=SQLiteDatabase.openDatabase(string,null,0);
}
public ArrayList<String> getSymbols() {
ArrayList<String> arrayList = new ArrayList<>();
openDatabase();
Cursor cursor = database.rawQuery("SELECT *FROM symbols ", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()){
arrayList.add(cursor.getString( cursor.getColumnIndex("content")));
cursor.moveToNext();
}
cursor.close();
closeDatabase();
return arrayList;
}
public ArrayList<String> getHotName (){
ArrayList<String> arrayList = new ArrayList<>();
openDatabase();
Cursor cursor = database.rawQuery("SELECT *FROM hot_names", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()){
arrayList.add(cursor.getString( cursor.getColumnIndex("contents")));
cursor.moveToNext();
}
cursor.close();
closeDatabase();
return arrayList;
}
public ArrayList<String> getList(String string){
ArrayList<String> arrayList = new ArrayList<>();
this.openDatabase();
Cursor cursor = this.database.rawQuery("SELECT * FROM emotication_detail WHERE parent_id =?",new String[]{string});
cursor.moveToFirst();
while (!cursor.isAfterLast()){
arrayList.add( cursor.getString( cursor.getColumnIndex("content")) );
// item sample = new item(cursor.getInt(0),cursor.getString(1));
cursor.moveToNext();
}
cursor.close();
this.closeDatabase();
return arrayList;
}
public ArrayList<String> getCtgList (String string){
ArrayList<String> arrayList = new ArrayList<>();
openDatabase();
Cursor cursor = database.rawQuery("SELECT *FROM Category WHERE tag =?", new String[]{string});
cursor.moveToFirst();
while (!cursor.isAfterLast()){
arrayList.add(cursor.getString( cursor.getColumnIndex("content")));
cursor.moveToNext();
}
cursor.close();
closeDatabase();
return arrayList;
}
}
Error log:
Fatal Exception: android.database.sqlite.SQLiteException: no such table: Category (code 1 SQLITE_ERROR): , while compiling: SELECT *FROM Category WHERE tag =?
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1347)
at com.softtechbd.nickname_finder.Database.DBHelper.getCtgList(DBHelper.java:18)
at com.softtechbd.nickname_finder.Fragments.pick_category_list.onCreateView(pick_category_list.java:4)
at androidx.fragment.app.Fragment.R(Fragment.java:15)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:27)
at androidx.fragment.app.FragmentManagerImpl.b0(FragmentManagerImpl.java:49)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:42)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:6)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:7)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:88)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:4)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:2)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6758)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
I would suggest changing :-
private boolean databaseExists() {
File dbFile = mContext.getDatabasePath(DB_Name);
return dbFile.exists();
}
to :-
private boolean databaseExists() {
File dbFile = mContext.getDatabasePath(DB_Name);
if (dbFile.exists()) {
return true;
}
dbFile.mkdirs(); //<<<<<<<<<< creates the databases folder
return false;
}
along with removing the line this.getReadableDatabase();
The use of getReadableDatabase (or getWritableDatabase as they are effectively the same in most siutations) hides the real underlying issue which is that the databases folder not existing results in the copy failing. That is getReadableDatabase will create the missing databases folder.
Although this works for older devices, newer devices (Android 9+) default to using write-ahead logging (WAL). If a database is created using WAL then two additional files, the WAL file (database file name suffixed with -wal) and the shared memory file (database file name suffixed with -shm) are created.
If just the database file is overwritten (as per the comments) then the -wal file is incompatible with the new database and the attempt to open the database fails, the failure is captured and instead an empty database file is created and returned and hence the loss of any tables. Hence the issue that you are facing.
Creating the databases folder if the database file does not exist, eliminates the need to use getReadable database to create the databases folder and thus the creation of -wal and -shm files. Thus why getReadableDatabase should not be used prior to the copy of the assets file.
Alternately you could delete the -wal and -shm files if they exist, prior to the copy.
i.e. the comments
WAL instead of recording changes in the log allowing them to be rolled back (journal mode) writes the changes to the WAL file and they are applied to the actual database when committed, thus the WAL file is effectively part of the database (roll back is effectively deleting WAL file). You may wish to refer to https://sqlite.org/wal.html
I would also suggest NOT hard coding the database path in the line
FileOutputStream fileOutputStream = new FileOutputStream("/data/data/"+mContext.getPackageName()+"/databases/"+DB_Name);
but instead use mContext.getDatabasePath(DB_NAME) to get the path.
e.g.
FileOutputSream fileOutputStrean = new FileOutputStream(mContext.getDatabasePath(DB_NAME));
Note the above code has not been tested so it may contain some errors, rather it is the principle that is being communicated.
An alternative approach could be to force journal mode using the journal_mode pragma or the SQliteDatabase disableWriteAheadLogging method. https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#disableWriteAheadLogging()

android sqlite - table data cannot be updated

the table ( i.e. vaccines) structure is :
id- auto increment primary key
dose1_date - string
dose2_date - string
The DatabaseAccessor class is as follows. The initDB() and setVaccineDates methods are called from another activity. But the database is not updated. The logged message is found in the logcat however. The DatabaseHelper class is not shown here.
public class DatabaseAccessor {
public static DataBaseHelper myDbHelper = null;
public static SQLiteDatabase rdb = null;
public static SQLiteDatabase wdb = null;
public static synchronized final void initDB(Context context) throws Exception {
if (myDbHelper == null) {
myDbHelper = new DataBaseHelper(context);
myDbHelper.openDataBase();
rdb = myDbHelper.getReadableDatabase();
wdb = myDbHelper.getWritableDatabase();
}
}
public static void setVaccineDates(String birthDate) throws SQLException{
try {
String[] selections = null;
String qry = null;
qry = "select * from vaccines order by id";
Cursor cursor = wdb.rawQuery(qry, selections);
Log.d("update qry===== ", qry);
while (cursor.moveToNext()) {
int rowID = Integer.parseInt(cursor.getString(0));
ContentValues values = new ContentValues();
values.put("dose1_date","66666");
values.put("dose2_date","7777");
wdb.update("vaccines", values, "id=?", new String[] {String.valueOf(rowID)});
//wdb.close();
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
}// end of method setVaccineDates
}
What to do ?
Edit : If I uncomment the wdb.close() line , I see in logcat
'06-09 04:21:05.387: W/System.err(4144): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.cloudsoft.vaccine/databases/vaccines2.db
'
As a newbie in android it was just a mistake out of ignorance that this situation took place: after update operation I tried to find the changes in the database file (i.e. file with .db extension sitting inside assets folder in Eclipse) through sqlite browser . But what actually happens is the app running in the device (real one or emulator) has its own database which is created from the .db extension file inside assets folder and consequent database operations only affect the app's own database leaving no touch on the database inside the mentioned folder in Eclipse. And there is the way to watch the app's very own database in the running device in Eclipse's 'File Explorer' (in DDMS mode) with the help of Questoid SQlite Manager

SQLiteException: no such column: category, but column does exist

I'm creating an Android project and I have a "DBFunc" class that has multiple methods to handles queries called by the activities.
DBFunc.java
public int getTotalNumberOfQuestions (String table, String category) {
String selectQuery = "SELECT COUNT(*) FROM " + table + " WHERE category='" + category + "'";
// example
// SELECT COUNT(*) FROM questions WHERE category='History';
SQLiteDatabase database = this.getReadableDatabase();
Cursor c = database.rawQuery(selectQuery, null);
int ans = -1; // returns -1 if query unsuccessful
if (c.moveToFirst()) {
ans = c.getInt(0);
}
database.close();
c.close();
return ans;
}
I'm getting an error on the cursor, saying
android.database.sqlite.SQLiteException: no such column: category (code 1): , while compiling: SELECT COUNT(*) FROM questions WHERE category='Physics'
but I do have a category column in my questions table
When running this query through sqlite3 on the command prompt, it works and returns a number (e.g 1)
Here's what the schema looks like in "DB Browser for SQLite"
I really hope there's an easy solution, because I don't understand why it wouldn't work,
Thanks
EDIT 1:
#CL asked for the code that creates the database. The database is created in sqlite3 command line and passed into the program. But the query I used was
CREATE TABLE questions (questionId INTEGER PRIMARY KEY AUTOINCREMENT, question TEXT, option1 TEXT, option2 TEXT, option3 TEXT, option4 TEXT, category TEXT);
EDIT 2:
I did what #Uwe Partzsch sugested and used LIKE instead of ' '
String selectQuery = "SELECT * FROM " + table + " WHERE category LIKE '" + category + "'";
But now I'm getting a different error
no such table: questions
EDIT 3:
public class DBFunc extends SQLiteOpenHelper {
public static String DB_PATH ="/data/data/com.example.healyj36.quizapp/databases/";
public static String DB_NAME = "questions.db";
public static final int DB_VERSION = 1;
public static final String TB_NAME1 = "questions";
public static final String TB_NAME2 = "answers";
private SQLiteDatabase myDB;
private Context context;
public DBFunc(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
}
//Copy database from source code assets to device
public void copyDataBase() throws IOException {
try {
InputStream myInput = context.getAssets().open(DB_NAME);
String outputFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception e) {
Log.e("tle99 - copyDatabase", e.getMessage());
}
}
public void createDatabase() throws IOException {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
Log.e("tle99 - create", e.getMessage());
}
}
...
This is can exists 2 possiblities:
This problem can occurred from broken SQLite schema.
Your question is not about SQL Statement problem. but many developer can think SQL Statement problem about your question.
This case can check no demaged data in your database file. Although you can not use select fields and sql where clause by field name.
As a result, you can not use database file in your android code.
Exactly solution, I recommend recreate SQLite DB file, step by step.
You must be backup before use SQLite modification tool. (SQLite Manager, Browser, others db manage tools)
This problem occurred from your persistent data.
If you use the same file name for assets or raw data when run with modified data,
you can try uninstall previous installed app for refresh.
Probably you have added the category column latter and trying to reinstall after modifications.
Either do a clear data from the Settings>app>your_app and launc
or
Uninstall the app and then install again.
Delete your app data, also you can try LIKE instead of '='.
String selectQuery = "SELECT * FROM " + table + " WHERE category LIKE '" + category + "'";

How do i upgrade my pre-populated sqlite database on my device without re-creating tables?

I have my code below. It correctly reads my sqlite database file(that i have already created using the SQLite Database Browser) in my assets folder - moves it to the /data/data/packagename/databases/ path on my device then i am able to use a query and cursor to get my information and it works great. Code here:
public class DatabaseHelper extends SQLiteOpenHelper {
private Context myDbContext;
private static String dbName = "restaurant.db";
private static String outfilePath = "/data/data/dev.mypackage.com/databases/";
private static String path = outfilePath + dbName;
private static SQLiteDatabase db;
public DatabaseHelper(Context context){
super(context, dbName, null, 2);
this.myDbContext = context;
db = openDb();
String s = "select * from menu";
Cursor c = db.rawQuery(s, null);
Log.e("DB Constructor Row count", String.valueOf(c.getCount()).toString());
while(c.moveToNext()){
Log.e("DB Constructor", c.getString(c.getColumnIndex("category")));
Log.e("DB Constructor", c.getString(c.getColumnIndex("menuItem_id")));
Log.e("DB Constructor", c.getString(c.getColumnIndex("title")));
Log.e("DB Constructor", c.getString(c.getColumnIndex("desc")));
Log.e("DB Constructor", c.getString(c.getColumnIndex("price")));
Log.e("DB Constructor", c.getString(c.getColumnIndex("icon")));
}
c.deactivate();
c.close();
}
private void copyDataBase(File dbFile) throws IOException {
try{
InputStream dbStream = myDbContext.getAssets().open(dbName);
OutputStream newDbFile = new FileOutputStream(outfilePath + dbName);
byte[] buffer = new byte[1024];
int length;
while((length = dbStream.read(buffer)) > 0){
newDbFile.write(buffer);
}
newDbFile.flush();
newDbFile.close();
dbStream.close();
}
catch(IOException e){
throw new IOException("trying to copy the database - ERROR: " + e.getMessage());
}
}
private SQLiteDatabase openDb() throws SQLiteException{
File dbFile = myDbContext.getDatabasePath(dbName);
if(!dbFile.exists()){
Log.e("openDb", "file does not exist");
try {
copyDataBase(dbFile);
} catch (IOException e) {
throw new RuntimeException("Error creating source database", e);
}
}
return SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
}
public void loadRestaurantInfo(){
}
#Override
public void onCreate(SQLiteDatabase db){
// TODO Auto-generated method stub
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
Now i had to go back and add a row of information to one of the tables(in the database in the assets folder), using the SQLite Brower, - but that is not being reflected in my cursor output - I understand why this is happening - because if(!dbFile.exists()) fails so there is no copying to be done. So my question is - is what code do i need to add to make this work? I never created the tables with code so i dont see how useful the onUpgrade method is going to be for me.
You have three options:
Use onUpgrade() (preferred)
Delete the existing database and copy the new one (not a good idea)
Copy the data in the existing database, delete the existing database, copy the new database, insert data from old database into new database (too much work when the new database schema can be upgraded in onUpgrade).
So, to answer your question, you upgrade your database in onUpgrade() without having to recreate any tables.
On the other hand, if you just added a new row to a particular table, the database schema has not changed and you can just insert the new row at runtime... of course, not knowing what your application's purpose is this may not be a good idea as you can easily lose track of changes to your "static" database.
The "right" way to do things is quite different from how you've set out. Rather than go there, I'll assume you want to keep your current method of creating your database and I'll offer a suggestion to work with it. Add a table to your database which has a single row of meta data, which will include the database version (as well as anything else you like). If the database file already exists, open it and check the version. If the version is old, close it and replace it.

Categories

Resources