android java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow
Asked Answered
M

3

46

I am developing an application which download some files and save their text in file_content field to database. The file sizes can vary from some KBs to 10 MB. The app works for all sizes while saving. The problem occurs when using select statement on long file_content records. It gives

java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow

when fetching such rows. Are there any limits on field content size? If so, then why it is letting us to save and giving error while retrieving? Here is my code snipped that fetches row:

public String getFileContent(MyFile gc) {
        if(!isDBOpen()) {
            open();
        }
        try {
            String mQuery = "SELECT * FROM " + DBOpenHelper.TABLE_SAVED_FILES + " WHERE " + DBOpenHelper.COLUMN_ID + " = " + gc.id;
            Cursor mCursor = database.rawQuery(mQuery, null);
            if(mCursor.getCount() <= 0) {
                return null;
            }
            if(mCursor.moveToFirst()) {
                return getCursorRowContent(mCursor);
            }
        } catch (Exception e) {
            e.getMessage();
        }
        return null;
    }

    private String getCursorRowContent(Cursor mCursor) throws Exception {
        return mCursor.getString(mCursor.getColumnIndex(DBOpenHelper.COLUMN_FILE_CONTENT));
    }

Any idea what is going on? I have tested it on 2 to 3 devices.

Logcat output:

01-29 13:41:56.520: W/CursorWindow(4121): Window is full: requested allocation 5140987 bytes, free space 2096617 bytes, window size 2097152 bytes
01-29 13:41:56.520: E/CursorWindow(4121): Failed to read row 0, column 0 from a CursorWindow which has 0 rows, 9 columns.

01-29 13:43:30.932: W/System.err(4121): java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it. 
01-29 13:43:30.932: W/System.err(4121):     at android.database.CursorWindow.nativeGetLong(Native Method) 
01-29 13:43:30.932: W/System.err(4121):     at android.database.CursorWindow.getLong(CursorWindow.java:507) 
01-29 13:43:30.932: W/System.err(4121):     at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) 
01-29 13:43:30.936: W/System.err(4121):     at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:220) 
01-29 13:43:30.936: W/System.err(4121):     at android.database.AbstractCursor.moveToNext(AbstractCursor.java:245) 
01-29 13:43:30.940: W/System.err(4121):     at com.nxb.cachehead.bl.PocketQueryDataSource.getGeoCacheContent(PocketQueryDataSource.java:97) 01-29 13:43:30.940: W/System.err(4121):     at com.nxb.cachehead.bl.GPXFileCopyAsyncTask.doInBackground(GPXFileCopyAsyncTask.java:27) 
01-29 13:43:30.940: W/System.err(4121):     at com.nxb.cachehead.bl.GPXFileCopyAsyncTask.doInBackground(GPXFileCopyAsyncTask.java:1) 
01-29 13:43:30.940: W/System.err(4121):     at android.os.AsyncTask$2.call(AsyncTask.java:287) 
01-29 13:43:30.944: W/System.err(4121):     at java.util.concurrent.FutureTask.run(FutureTask.java:234) 
01-29 13:43:30.944: W/System.err(4121):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 
01-29 13:43:30.948: W/System.err(4121):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
01-29 13:43:30.948: W/System.err(4121):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
01-29 13:43:30.948: W/System.err(4121):     at java.lang.Thread.run(Thread.java:856)
Miculek answered 29/1, 2014 at 13:29 Comment(1)
I've reported this ticket to Google, it's a bad API that allows developers to get into this situation. Star and comment on this issue to get attention from Google to address it: issuetracker.google.com/issues/145977220Collado
R
98

01-29 13:41:56.520: W/CursorWindow(4121): Window is full: requested allocation 5140987 bytes, free space 2096617 bytes, window size 2097152 bytes

Android SQLite returns rows in cursor windows that have the maximum size of 2MB as specified by config_cursorWindowSize. If your row exceeds this limit, you'll get this error.

Storing large data in sqlite database is not a good idea anyway. Store files in filesystem and paths in database.

Rameses answered 29/1, 2014 at 13:47 Comment(10)
Yeah I know that it is not a good idea to store large files in database but I have to perform different search operations on downloaded files later on. So the content needs to be in database.Miculek
You'll have to index the data for such purposes.Rameses
wow finally found the answer to my problem here! I'm holding a large JSON string in my database- no wonder i couldn't fetch it. probably larger than 2MB. nice.Dollydolman
@binnyb How you can achieve to store large json more than 2 MB on database and select it?Blowfish
@MIkkaMarmik you don't. You should store the content on the filesystem and save the path to the content in the database, rather than storing the content itselfDollydolman
It is strange that android lets you serialise the data without any size constraint. Now, because of a bug in my app, for some users one of the rows is bloated and can not be read! Is there a way to read it once may be with some performance overhead, so as to fix it?Potts
Omg, I could never find this, there's too much documentation to read... Thank you very much.Dettmer
any fixes yet??Galitea
Maybe you can use @ColumnInfo(typeAffinity = ColumnInfo.BLOB) on the image field and store it as a ByteArrayMelanesian
Why does the Android API allow you to write a 2 MB row into your DB but then crashes your app with IllegalStateException when you try to read it? Sqlite handles this just fine but the Android wrapper around it can't. Broken API.Collado
E
1

In the case of using React Native, it works for me:

Add this piece of code at the end of onCreate() in MainApplication.java

try {
  Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
  field.setAccessible(true);
  field.set(null, 100 * 1024 * 1024); //100MB
  } catch (Exception e) {
 if (BuildConfig.DEBUG) {
  e.printStackTrace();
  }
  }

Also import these on top of the MainApplication.java

import android.database.CursorWindow;
import java.lang.reflect.Field;
Endor answered 12/1, 2022 at 16:18 Comment(0)
I
-1

In case you want to save images as bytes, Another way to do this is, while compressing the bitmap, set the quality to 0.

Ire answered 9/11, 2018 at 20:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.