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
02 : 27
SOLVED # 1118 Row size too large 8126. Changing some columns to TEXT or BLOB
54 : 07
End-To-End: ML with SQL in BigQuery (BQML) [notebook 03a]
12 : 41
Comment fixer l’Erreur : «Row too big to fit into CursorWindow» ? | Compresser une image Sqlite
Super Développeur — Nadim GOUIA
03 : 45
MySQL error: The maximum column size is 767 bytes
18 : 44
BigQuery Analytic Function and ROW_NUMBER()
03 : 29
SOLVED MY SQL ERROR: Row size too large 8126 Changing some columns to TEXT or BLOB
11 : 40
BULK Write Back to SQL from Power BI
00 : 22
01 : 08
SQL Error (1118)Row size too large. The maximum row size for the used table type, not counting BLOB
50 : 08
T-SQL Challenge: Quickly Finding Rows with the Largest Strings
12 : 45
Insert One Million Rows into SQL Server — How to Use SqlBulkCopy
Sean MacKenzie Data Engineering
01 : 10
Fixed : MySQL: Error Code: 1118 | Row size too large
04 : 11
(Solved) Mengatasi Error Import / Restore Backup Database Mysql Workbench — Row size too large 8126
04 : 27
SOLVED Row size too large 8126 Changing some columns to TEXT or BLOB
01 : 09
Why the rows returns by explain is not equal to count() — 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
-
#2
First step is to close resultSet when done with it. I don’t know whether it is related to this error or not.
-
#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?
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
-
#4
resultSet.Position = rowCount
Something looks unusual here.
-
#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.
-
#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) = ?
-
#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
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.
-
#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.
-
#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