5

I recently published an app to the market place. From the developers console it seems about 1-2% of my users are having this issue. 1-2% is small but people are more inclined to leave comments when something doesn't work rather than when it does which could negatively effect downloads.

Unfortunately the developers console only lists the platform as 'other', but my app is available to those with SDK 1.6+. I'm also unable to recreate this issue and no user has contacted me directly so I'm unable to get any more information about the devices it fails on.

Here is the stack

android.database.sqlite.SQLiteException: no such table: QUESTIONS: , while compiling: SELECT * FROM QUESTIONS WHERE DIFFICULTY=2 ORDER BY RANDOM() LIMIT 20
at android.database.sqlite.SQLiteCompiledSql.native_compile(Native Method)
at android.database.sqlite.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:80)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1434)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1404)
at com.app.myapp.db.DBHelper.getQuestionSet(DBHelper.java:140)
at com.app.myapp.SplashActivity.getQuestionSetFromDb(SplashActivity.java:109)
at com.app.myapp.SplashActivity.onClick(SplashActivity.java:58)
at android.view.View.performClick(View.java:2421)
at android.view.View$PerformClick.run(View.java:8867)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:5068)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
at dalvik.system.NativeStart.main(Native Method)

getQuestionSetFromDb(SplashActivity.java:109) refers to

List<Question> questions = myDbHelper.getQuestionSet(diff, numQuestions);

Which refers to

public List<Question> getQuestionSet(int difficulty, int numQ){
    List<Question> questionSet = new ArrayList<Question>();
    Cursor c = myDataBase.rawQuery("SELECT * FROM QUESTIONS WHERE DIFFICULTY=" + difficulty +
            " ORDER BY RANDOM() LIMIT " + numQ, null);
    while (c.moveToNext()){
        //Log.d("QUESTION", "Question Found in DB: " + c.getString(1));
        Question q = new Question();
        q.setQuestion(c.getString(1));
        q.setAnswer(c.getString(2));
        q.setOption1(c.getString(3));
        q.setOption2(c.getString(4));
        q.setOption3(c.getString(5));
        q.setRating(difficulty);
        questionSet.add(q);
    }
    return questionSet;
}

}

Does anyone know of a probable cause? It's strange this is only happening with a small amount of installs and being unable to determine the SDK level/device they are using makes it more difficult.

Any help is appreciated

EDIT: Due to the responses I'm including how the db is created.

First, my activity has this (this is the same method which causes the crash)

    private List<Question> getQuestionSetFromDb() throws Error {
    int diff = getDifficultySettings();
    int numQuestions = getNumQuestions();
    DBHelper myDbHelper = new DBHelper(this);
    try {
        myDbHelper.createDataBase();
    } catch (IOException ioe) {
        throw new Error("Unable to create database");
    }
    try {
        myDbHelper.openDataBase();
    }catch(SQLException sqle){
        throw sqle;
    }
    List<Question> questions = myDbHelper.getQuestionSet(diff, numQuestions);
    myDbHelper.close();
    return questions;
}

myDBhelper.createdatabase() calls

public void createDataBase() throws IOException{

    boolean dbExist = checkDataBase();
    if(!dbExist)
    {
        //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.
        this.getReadableDatabase();

        try {
            copyDataBase(); 
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
}

checkDatabase()

    private boolean checkDataBase(){
    SQLiteDatabase checkDB = null;
    try{
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    }catch(SQLiteException e){
        //database does't exist yet.
    }
    if(checkDB != null){
        checkDB.close();
    }

    return checkDB != null ? true : false;
}

copyDatabase()

    private void copyDataBase() throws IOException{

    //Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(DB_NAME);

    // Path to the just created empty db
    String outFileName = DB_PATH + DB_NAME;

    //Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    //transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer))>0){
        myOutput.write(buffer, 0, length);
    }

    //Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

}

Variables

    private static String DB_PATH = "/data/data/com.app.myapp/databases/";
private static String DB_NAME = "questionsDb";
private SQLiteDatabase myDataBase; 
private final Context myContext;

Apoligies, I really should have included this initially

PapaJon
  • 63
  • 1
  • 4
  • Did you recently upgrade the DB schema to include the Questions table? – hooked82 Aug 25 '11 at 20:16
  • No, the database tables have always been the same. Since I've uploaded to the market there have been no database changes at all. – PapaJon Aug 25 '11 at 21:02
  • Well the error seems obvious; your table can't be found. So I would start looking at the part where it gets created, making sure it does get created at all. Also it might be an idea to catch this specific error and then create the table if it occurs. – Will Kru Aug 25 '11 at 21:15
  • I would like to see the create statement. Possibly an upper-/lower-case conflict? Do you use other constraints as PRIMARY KEY/NOT NULL? – Harald Wilhelm Aug 25 '11 at 21:18
  • @Will Kru, as stated, this only affects a very small amount of users so usually the database is created fine - I cannot recreate this error and I'm unaware of what SDK the users are running. I will edit my post to include how I'm creating and checking the DB. – PapaJon Aug 25 '11 at 21:24
  • @Harald - Referring upper/lower case conflict, could the issue be because DB_NAME = "questionsDb" has a capital 'D'? Would the error be something completely different if it didn't find the db at all? Btw, the questions table is all lowercase in the db itself. – PapaJon Aug 25 '11 at 21:33
  • Are `int`s automatically coerced to strings when the concatenate operator is used? – Tim Aug 25 '11 at 21:34

2 Answers2

0

The error reports about a missing "QUESTIONS" database. DB_NAME is "questionsDb".

The int difficulty, appended with + to a string, puzzles me too (was already reported from another user earlier in this thread).

Harald Wilhelm
  • 6,656
  • 11
  • 67
  • 85
0

I just feel the way you are creating the database is causing the problem. There is nothing wrong with it; as you said it works on 98% of the devices.

In my opinion, you are probably better off extending SQLiteOpenHelper. This takes care of creating your database if it doesn't exist and you don't have to do any checks manually that you do.

Raunak
  • 6,427
  • 9
  • 40
  • 52