Row too big to fit into cursorwindow ошибка

I keep hitting this annoying message !

When data finished insert into local database, I saw this message

JNI critical lock held for 30.083ms on Thread[27,tid=23883,Runnable,Thread*=0xce150a00,peer=0x12cc0190,"Sqflite"]

If I select data from the table, I get

W/CursorWindow(23809): Window is full: requested allocation 3095146 bytes, free space 2096696 bytes, window size 2097152 bytes
E/SQLiteQuery(23809): exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT * FROM description_table;
I/flutter (23809): DatabaseException(Row too big to fit into CursorWindow requiredPos=0, totalRows=1) sql 'SELECT * FROM defect_description_table;' args []}

I don’t have any blob data, all are String. So why would this happened?

Here the json structure

[{ "id": 1, "name": "Descriptions","data": [{..},{...} ... ]},{....},{....}]

I think the issue is on the data list,because it contains lot of data(it has 10298) ?

What is the solution for this?

My insert method

Future insertData(
      BuildContext context, String urls, String accessToken) async {
    CategoryTableData categoryData = CategoryTableData();
    try {
      var desc = List<Desc>();
      var headers = {
        'authorization': "Bearer" + " " + accessToken,
        "Accept": "application/json"
      };
      var url = xxx;
      var response = await http.get(url, headers: headers);
      var res = json.decode(response.body);
      for (var i in res) {
        if (i['name'] == "Descriptions") {
          desc.add(Desc(
              id: i['id'], name: i['name'], data: i['data']));
        }
      }
      await dao.batch((b) {
        b.insertAll(_dao.descTable, desc);
      });
      categoryData = await _dao.selectAllCategories();
      return categoryData;
    } catch (e) {
      print(e);
      categoryData = await _dao.selectAllCategories();
      return categoryData;
    }
  }

Desc

class Desc extends Table {
  IntColumn get id => integer().nullable()();
  TextColumn get name => text().named("name").nullable()();
  TextColumn get data => text().map(const ListConverter()).nullable()();
}

Expected Behavior

The query with large data should succeed without an error.

Current Behavior

When trying to a do a SELECT on large rows, the query fails with error:

Row too big to fit into CursorWindow

Steps to Reproduce (for bugs)

This is affecting several users of Joplin:

laurent22/joplin#1771
laurent22/joplin#1690

and it happens when trying to read or write to the database large text data (some users mention 4MB).

It seems to have started only recently so it could be due to a React Native upgrade or other change to the Android build.

What I’m wondering is, is there any way to prevent this error, for example some option that can be set to increase the available memory?

The Joplin desktop application uses the same architecture (but of course with a different sqlite package) and this error doesn’t happen, so it seems it’s possible to prevent it. 4MB is a bit large but not huge either so it seems it should work, at least with an option.

Your Environment

  • React Native SQLite Storage Version used: 3.3.10
  • React Native version used: 0.59.10
  • Operating System and version (simulator or device): Android (device)
  • Link to your project: https://github.com/laurent22/joplin

Solution 1

This worked for me, you have to put it on your Main Activity.

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

Solution 2

Try this new constructor method above API 28. Maybe you should set a limited windowSizeBytes for CursorWindow and try-catch the exception.

Related cts code (https://android.googlesource.com/platform/cts/+/master/tests/tests/database/src/android/database/sqlite/cts/SQLiteCursorTest.java) :

    public void testRowTooBig() {
        mDatabase.execSQL("CREATE TABLE Tst (Txt BLOB NOT NULL);");
        byte[] testArr = new byte[10000];
        Arrays.fill(testArr, (byte) 1);
        for (int i = 0; i < 10; i++) {
            mDatabase.execSQL("INSERT INTO Tst VALUES (?)", new Object[]{testArr});
        }
        // Now reduce window size, so that no rows can fit
        Cursor cursor = mDatabase.rawQuery("SELECT * FROM TST", null);
        CursorWindow cw = new CursorWindow("test", 5000);
        AbstractWindowedCursor ac = (AbstractWindowedCursor) cursor;
        ac.setWindow(cw);
        try {
            ac.moveToNext();
            fail("Exception is expected when row exceeds CursorWindow size");
        } catch (SQLiteBlobTooBigException expected) {
        }
    }

Others:

Since this article was originally published, we’ve added new APIs in
the Android P developer preview to improve the behavior above. The
platform now allows apps to disable the ⅓ of a window heuristic and
configure CursorWindow size.

Ref Link:
https://medium.com/androiddevelopers/large-database-queries-on-android-cb043ae626e8

Solution 3

Try to scale bitmap:

Bitmap.createScaledBitmap

Related videos on Youtube

SOLVED # 1118 Row size too large 8126. Changing some columns to TEXT or BLOB

02 : 27

SOLVED # 1118 Row size too large 8126. Changing some columns to TEXT or BLOB

End-To-End: ML with SQL in BigQuery (BQML) [notebook 03a]

54 : 07

End-To-End: ML with SQL in BigQuery (BQML) [notebook 03a]

Comment fixer l'Erreur : "Row too big to fit into CursorWindow" ? | Compresser une image Sqlite

12 : 41

Comment fixer l’Erreur : «Row too big to fit into CursorWindow» ? | Compresser une image Sqlite

Super Développeur — Nadim GOUIA

MySQL error: The maximum column size is 767 bytes

03 : 45

MySQL error: The maximum column size is 767 bytes

BigQuery Analytic Function and ROW_NUMBER()

18 : 44

BigQuery Analytic Function and ROW_NUMBER()

SOLVED MY SQL ERROR: Row size too large  8126  Changing some columns to TEXT or BLOB

03 : 29

SOLVED MY SQL ERROR: Row size too large 8126 Changing some columns to TEXT or BLOB

BULK Write Back to SQL from Power BI

11 : 40

BULK Write Back to SQL from Power BI

IPhone vs Nokia phone

00 : 22

SQL Error (1118)Row size too large. The maximum row size for the used table type, not counting BLOB

01 : 08

SQL Error (1118)Row size too large. The maximum row size for the used table type, not counting BLOB

T-SQL Challenge: Quickly Finding Rows with the Largest Strings

50 : 08

T-SQL Challenge: Quickly Finding Rows with the Largest Strings

Insert One Million Rows into SQL Server - How to Use SqlBulkCopy

12 : 45

Insert One Million Rows into SQL Server — How to Use SqlBulkCopy

Sean MacKenzie Data Engineering

Fixed : MySQL: Error Code: 1118 | Row size too large

01 : 10

Fixed : MySQL: Error Code: 1118 | Row size too large

(Solved) Mengatasi Error Import / Restore Backup Database Mysql Workbench - Row size too large 8126

04 : 11

(Solved) Mengatasi Error Import / Restore Backup Database Mysql Workbench — Row size too large 8126

SOLVED Row size too large  8126 Changing some columns to TEXT or BLOB

04 : 27

SOLVED Row size too large 8126 Changing some columns to TEXT or BLOB

Why the rows returns by explain is not equal to count() - MySQL

01 : 09

Why the rows returns by explain is not equal to count() — MySQL

Row size too large error in mysql create table query - MySQL

01 : 19

Row size too large error in mysql create table query — MySQL

Comments

  • I am getting below exception only in android 9, after reinstalling everything looks good,

    Exception:

    android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1...
    

    Code:

    Cursor cursor = database.query(......);
        if(cursor == null || cursor.getCount() < 0) { //Here is the error
            Log.d("Error", "count : null");
            return "";
        }
    

    Edited:

    java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:354)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)
    
    Caused by: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
    at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
    at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:859)
    at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836)
    at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:149)
    at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:137)
    

    Thanks in advance guys

  • This absolutely solved the problem, so thank you and +1. Quick follow-up question, does anyone know if this could trigger any cascaded external Runtime exceptions? IE, if a user has <100mb of free space on their device, will this throw an exception? Or work fine as it is in RAM?

Recents

Related

Erel


  • #2

First step is to close resultSet when done with it. I don’t know whether it is related to this error or not.

jahswant


  • #3

It appears that Cursors in android can only hold up to 1 MB of data.

What would be the most efficient way to pull the maximum number of rows from a table in a SQLite database that stays under the 1 MB limit?

stackoverflow.com

Android Cursor maximum size

It appears that Cursors in android can only hold up to 1 MB of data. What would be the most efficient way to pull the maximum number of rows from a table in a SQLite database that stays under th…


stackoverflow.com

stackoverflow.com

aeric


  • #4

resultSet.Position = rowCount

Something looks unusual here.

DonManfred


  • #5

Is there anything wrong with my code?

what is the amount of data being returned by the query? Only a few varchar fields or are there blobs you read from the database?

You told only 3 columns. What data are in these three columns? How big is the data from these columsns?

Based on the error the amount of data are to big to the resultset. SQLite has a 1-2mb limit you can fetch from the Database at once.

  • #6

what is the amount of data being returned by the query? Only a few varchar fields or are there blobs you read from the database?

You told only 3 columns. What data are in these three columns? How big is the data from these columsns?

Based on the error the amount of data are to big to the resultset. SQLite has a 1-2mb limit you can fetch from the Database at once.

Hi Don,

The amount of data is 8 row.

The field type is Text, no blob.

The data is text only, not more than 50 characters each column.

  • #7

Something looks unusual here.

Hi Aeric,

It looks like I have to set the Result Set row Position.
If I delete that, I got another error.
Will post it in another thread.

99.99% the Function works fine.
Even that 8 rows returned, when I debug it, it return 7 row then error at the 8.

aeric


  • #8

Can you post a small example with the db?

  • #9

Can you post a small example with the db?

Hi Aeric,

This is the table

sqlLite.ExecNonQuery("CREATE TABLE IF NOT EXISTS SIV (SIVCode TEXT, " _
    & "CompanyNo TEXT, " _
    & "StoreCode TEXT, " _
    & "SIVDate DATE, " _
    & "Description TEXT, " _
    & "IsSync TEXT)")

sqlLite.ExecNonQuery("CREATE TABLE IF NOT EXISTS SIVDetails (SIVCode TEXT, " _
    & "CompanyNo TEXT, " _
    & "StockSeq TEXT, " _
    & "StockItemCode TEXT, " _
    & "Quantity TEXT, " _
    & "Price TEXT, " _
    & "Amount TEXT, " _
    & "Description TEXT, " _
    & "ItemType TEXT, " _
    & "IsSync TEXT)")

This is the query

SELECT DISTINCT SIV.SIVCode AS SIVCode, SIV.SIVDate, SIV.CompanyNo
FROM SIV LEFT JOIN SIVDetails SIVD ON SIV.SIVCode = SIVD.SIVCode AND SIV.CompanyNo = SIVD.CompanyNo
WHERE (SIV.IsSync = '0' OR SIVD.IsSync = '0') AND
CAST(strftime('%Y', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 1, 2) || '-' ||
SUBSTR(siv.SIVDate, 4, 2)) As INTEGER) = ?
AND CAST(strftime('%m', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 1, 2) || '-' ||
SUBSTR(SIV.SIVDate, 4, 2)) AS INTEGER) = ?

aeric


  • #10

resultSet.Position = rowCount

There is no method call Position in Resultset. It only existed in Cursor.

You didn’t provide sample data. I add some dummy data myself and run with no problem.

Public Sub SelectArray(query As String, param() As Object) As List
    Dim result As List
    result.Initialize
  
    Dim resultSet As ResultSet = DB.ExecQuery2(query, param)
  
    Dim columnCount As Int = resultSet.ColumnCount
    'Dim rowCount As Int = 0
  
    Do While resultSet.NextRow
        Dim value(columnCount) As Object
      
        For j = 0 To columnCount - 1
            'resultSet.Position = rowCount
            'value(j) = resultSet.GetString(resultSet.GetColumnName(j))
            value(j) = resultSet.GetString2(j)
        Next
      
        result.Add(value)
        'rowCount = rowCount + 1
    Loop
    resultSet.Close
    Return result
End Sub

If your SIVDate is in «dd-MM-YYYY» format then the query should be:

    SELECT DISTINCT
    SIV.SIVCode AS SIVCode, SIV.SIVDate, SIV.CompanyNo
    FROM SIV
    LEFT JOIN SIVDetails SIVD
    ON SIV.SIVCode = SIVD.SIVCode
    AND SIV.CompanyNo = SIVD.CompanyNo
    WHERE (SIV.IsSync = '0' OR SIVD.IsSync = '0')
    AND CAST(strftime('%Y', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 4, 2) || '-' ||
    SUBSTR(siv.SIVDate, 1, 2)) As INTEGER) = ?
    AND CAST(strftime('%m', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 4, 2) || '-' ||
    SUBSTR(SIV.SIVDate, 1, 2)) AS INTEGER) = ?

toby

toby

Well-Known Member


  • #11

A simple project with sample data should be provided in order for other people to better help you.

  • #12

There is no method call Position in Resultset. It only existed in Cursor.

You didn’t provide sample data. I add some dummy data myself and run with no problem.

Public Sub SelectArray(query As String, param() As Object) As List
    Dim result As List
    result.Initialize
 
    Dim resultSet As ResultSet = DB.ExecQuery2(query, param)
 
    Dim columnCount As Int = resultSet.ColumnCount
    'Dim rowCount As Int = 0
 
    Do While resultSet.NextRow
        Dim value(columnCount) As Object
    
        For j = 0 To columnCount - 1
            'resultSet.Position = rowCount
            'value(j) = resultSet.GetString(resultSet.GetColumnName(j))
            value(j) = resultSet.GetString2(j)
        Next
    
        result.Add(value)
        'rowCount = rowCount + 1
    Loop
    resultSet.Close
    Return result
End Sub

If your SIVDate is in «dd-MM-YYYY» format then the query should be:

    SELECT DISTINCT
    SIV.SIVCode AS SIVCode, SIV.SIVDate, SIV.CompanyNo
    FROM SIV
    LEFT JOIN SIVDetails SIVD
    ON SIV.SIVCode = SIVD.SIVCode
    AND SIV.CompanyNo = SIVD.CompanyNo
    WHERE (SIV.IsSync = '0' OR SIVD.IsSync = '0')
    AND CAST(strftime('%Y', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 4, 2) || '-' ||
    SUBSTR(siv.SIVDate, 1, 2)) As INTEGER) = ?
    AND CAST(strftime('%m', SUBSTR(SIV.SIVDate, 7, 4) || '-' || SUBSTR(SIV.SIVDate, 4, 2) || '-' ||
    SUBSTR(SIV.SIVDate, 1, 2)) AS INTEGER) = ?

Hi Aeric,

I try your solution but it still error.

The sample data I get from the query is

SIVCode : SIV202211918655
This value is based on this Code

"SIV" & DateTime.GetYear(DateTime.Now) & "" & DateTime.GetMonth(DateTime.Now) _
        & "" & DateTime.GetDayOfMonth(DateTime.Now) & "" & DateTime.GetHour(DateTime.Now) _
        & "" & DateTime.GetMinute(DateTime.Now) & "" & DateTime.GetSecond(DateTime.Now)

SIVDate : 2022-01-19 (Normal date format)
CompanyNo : S01M

Is there a max length for a column?
I try to get SIVCode only from the query, it give me same error.
But if I ditch SIVCode, it work just fine.

aeric


  • #13

«SIV» & DateTime.GetYear(DateTime.Now) & «» & DateTime.GetMonth(DateTime.Now) _ & «» & DateTime.GetDayOfMonth(DateTime.Now) & «» & DateTime.GetHour(DateTime.Now) _ & «» & DateTime.GetMinute(DateTime.Now) & «» & DateTime.GetSecond(DateTime.Now)

Since we don’t have your actual data, it is difficult to keep continue make guesses.

The code you use to generate the SIVCode may generate inconsistent length because numbers like months could be 1 or 2 digit e.g. Jan=1 (1 digit) and Dec=12 (2 digit). This is same with day, hour, minute and seconds.

aeric


  • #14

Try this Sub to generate the SIVCode:

Sub GenerateSIVCode As String
    DateTime.DateFormat = "yyyyMMdd"
    DateTime.TimeFormat = "HHmmss"
    Dim CurrentTime As String = DateTime.Date(DateTime.Now) & DateTime.Time(DateTime.Now)
    'Log(CurrentTime)
    Return "SIV" & CurrentTime
End Sub

  • #15

This value is based on this Code

@aeric and @toby have been asking you to upload a simple project, so you get help, but you keep ignoring their call. Looking at your queries and code, you are complicating things unnecessarily. Upload a project and you will get help. SQLite is a very popular subject and many members are so good at it and dying to help you.
Here is another simple form for aeric’s function: This or @aeric’ s function are a lot easier than what you are trying to do:

Sub GenerateSIVCode As String
    DateTime.DateFormat = "yyyyMMddHHmmss"
    Return "SIV" & DateTime.Date(DateTime.Now)
End Sub

I am getting below exception only in android 9, after reinstalling everything looks good,

Exception:

android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1...

Code:

Cursor cursor = database.query(......);
    if(cursor == null || cursor.getCount() < 0) { //Here is the error
        Log.d("Error", "count : null");
        return "";
    }

Edited:

java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)

Caused by: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
at android.database.sqlite.SQLiteConnection.nativeExecuteForCursorWindow(Native Method)
at android.database.sqlite.SQLiteConnection.executeForCursorWindow(SQLiteConnection.java:859)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:836)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:149)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:137)

Thanks in advance guys

This worked for me, you have to put it on your Main Activity.

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

Try to scale bitmap:

Bitmap.createScaledBitmap

Try this new constructor method above API 28. Maybe you should set a limited windowSizeBytes for CursorWindow and try-catch the exception.

Related cts code (https://android.googlesource.com/platform/cts/+/master/tests/tests/database/src/android/database/sqlite/cts/SQLiteCursorTest.java) :

    public void testRowTooBig() {
        mDatabase.execSQL("CREATE TABLE Tst (Txt BLOB NOT NULL);");
        byte[] testArr = new byte[10000];
        Arrays.fill(testArr, (byte) 1);
        for (int i = 0; i < 10; i++) {
            mDatabase.execSQL("INSERT INTO Tst VALUES (?)", new Object[]{testArr});
        }
        // Now reduce window size, so that no rows can fit
        Cursor cursor = mDatabase.rawQuery("SELECT * FROM TST", null);
        CursorWindow cw = new CursorWindow("test", 5000);
        AbstractWindowedCursor ac = (AbstractWindowedCursor) cursor;
        ac.setWindow(cw);
        try {
            ac.moveToNext();
            fail("Exception is expected when row exceeds CursorWindow size");
        } catch (SQLiteBlobTooBigException expected) {
        }
    }

Others:

Since this article was originally published, we’ve added new APIs in
the Android P developer preview to improve the behavior above. The
platform now allows apps to disable the ⅓ of a window heuristic and
configure CursorWindow size.

Ref Link:
https://medium.com/androiddevelopers/large-database-queries-on-android-cb043ae626e8

Возможно, вам также будет интересно:

  • Router application exe ошибка приложения
  • Router application exe ошибка при выключении компьютера
  • Router application exe ошибка при выключении windows 11
  • Roundcube ошибка соединения сбой подключения к серверу
  • Roundcube smtp ошибка 550 невозможно добавить получателя

  • Понравилась статья? Поделить с друзьями:
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии