2

I have created the class below for saving data to a SQLite database. It is simply a key/value mapping, as you can see. The KEY is a TEXT field and the VALUE is a BLOB.

It works perfectly except in one scenario: I use "add" to add a String which is approximately 2,500,000 characters in length. In fact, it is a JSON-encoded string (which I have also tried applying a javascript-style encodeURIComponent to, as well, in attempts to make sure that there are no illegal characters interfering).

In this scenario, the value gets added successfully (no errors thrown, add() returns true). However, when I call get(key) immediately afterwards, the IllegalStateException is thrown from the cursor.getString(0).

Specifically:

"Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it." (id=830026207728) 

I have inspected the cursor object and don't see anything wrong with it (mCount==1, mColumns==String[1], etc).

class DatabaseHandler extends SQLiteOpenHelper {

    // All Static variables
    // Database Version
    private static final int DATABASE_VERSION = 2;

    // Contacts Table Columns names
    private static final String KEY_KEY = "key";
    private static final String KEY_VAL = "value";

    public DatabaseHandler(Context context) {
        super(context, Defines.DATA_PREFIX, null, DATABASE_VERSION);
    }

    public String getTableName() {
        return "storage";
    }

    // Creating Tables
    @Override
    public void onCreate(SQLiteDatabase db) {
        String q = "CREATE TABLE " + this.getTableName() + "(" + KEY_KEY + " TEXT PRIMARY KEY," + KEY_VAL + " BLOB" + ")";
        db.execSQL(q);
    }

    // Upgrading database
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + this.getTableName());

        // Create tables again
        onCreate(db);
    }

    boolean add(String key, String value) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_KEY, key); // Contact Name
        values.put(KEY_VAL, value); // Contact Phone

        // Inserting Row
        long res = db.insertOrThrow(this.getTableName(), null, values);
        db.close(); // Closing database connection
        return res >= 0;
    }

    String get(String key) {
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.query(this.getTableName(), new String[] { KEY_VAL }, KEY_KEY + "=?", new String[] { key }, null, null, null, null);
        if (cursor != null)
            cursor.moveToFirst();

        if(cursor == null)
            return null;

        String ret = null;
        try {
            ret = cursor.getString(0);
        } catch(CursorIndexOutOfBoundsException e) {
            ret = null;
        } catch(IllegalStateException e) {
            ret = null;
        }
        cursor.close();
        return ret;
    }

    int count(String key) {
        String countQuery = "SELECT  * FROM " + this.getTableName()+" WHERE "+KEY_KEY+" = ?";
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(countQuery, new String[] { key });
        int ret = cursor.getCount();;
        cursor.close();

        // return count
        return ret;
    }

    void delete(String key) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(this.getTableName(), KEY_KEY + " = ?", new String[] { key });
        db.close();
    }

    int update(String key, String value)
    {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_KEY, key);
        values.put(KEY_VAL, value);

        // updating row
        return db.update(this.getTableName(), values, KEY_KEY + " = ?", new String[] { key });
    }
}
Zane Claes
  • 14,732
  • 15
  • 74
  • 131

1 Answers1

3

Upon further investigation, the console window told me that the "Cursor Window" is full, eg, that it was out of space. See this thread: Android: Cursor Window is full

My solution was to "chunk" the data. Eg, the "add" function detects if the string is > a fixed length, in which case it stores multiple entries for the string (uses many rows). The "get" function then detects this and re-assembles the chunks.

Community
  • 1
  • 1
Zane Claes
  • 14,732
  • 15
  • 74
  • 131