Is there any limit on sqlite query size? - android

Is there any limit on how big the selection statement can be?
for example suppose I have 100 failed student as selection, will my below code work?
ArrayList<Long> ids_toupdate = getFailedStudents();// has size 100.
String selection = String.format(Locale.US, STUDENT._ID + " IN (%s)",TextUtils.join(", ", ids_toupdate));
ContentValues cv = new ContentValues();
cv.put(RawContacts.FAILED, 1);
getContentResolver().update(STUDENT.CONTENT_URI,cv, selection, null);

Roughly speaking the default limit is 1,000,000 bytes or 1,000,000 characters, so unless your 'students' are over 100,000 characters each your statement should be fine.
The following is taken from http://www.sqlite.org/limits.html
Maximum Length Of An SQL Statement
The maximum number of bytes in the text of an SQL statement is limited to SQLITE_MAX_SQL_LENGTH which defaults to 1000000. You can redefine this limit to be as large as the smaller of SQLITE_MAX_LENGTH and 1073741824.
If an SQL statement is limited to be a million bytes in length, then obviously you will not be able to insert multi-million byte strings by embedding them as literals inside of INSERT statements. But you should not do that anyway. Use host parameters for your data. Prepare short SQL statements like this:
INSERT INTO tab1 VALUES(?,?,?);
Then use the sqlite3_bind_XXXX() functions to bind your large string values to the SQL statement. The use of binding obviates the need to escape quote characters in the string, reducing the risk of SQL injection attacks. It is also runs faster since the large string does not need to be parsed or copied as much.
The maximum length of an SQL statement can be lowered at run-time using the sqlite3_limit(db,SQLITE_LIMIT_SQL_LENGTH,size) interface.
EDIT: 26/10/2022 As Tobias explains in his comment, the linked article now depicts the default max length as follows:
Maximum Length Of An SQL Statement
The maximum number of bytes in the text of an SQL statement is limited to SQLITE_MAX_SQL_LENGTH which defaults to 1,000,000,000.

There is also SQLITE_MAX_VARIABLE_NUMBER which limits the number of variables in a query. The default value is 999 but some distributions are compiled with higher settings.

Related

Does SQLite `NOT IN` parameter have any size limit?

I have an SQLite DB where I perform a query like
Select * from table where col_name NOT IN ('val1','val2')
Basically I'm getting a huge list of values from server and I need to select the ones which is not present in the list given.
Currently its working fine, No issues. But the number of values from server becomes huge as the server DB is getting updated frequently.
So, I may get thousands of String values which I need to pass to the NOT IN
My question is, Will it cause any perfomance issue in the future? Does the NOT IN parameter have any size restriction? (like max 10000 values you can check)?
Will it cause any crash at some point?
This is an official reference about various limitation in sqlite. I think the Maximum Length Of An SQL Statement may related to your case. Default value is 1000000, and it is adjustable.
Except this I don't think any limitation existed for numbers of parameter of NOT IN clause.
With more than a few values to test for, you're better off putting them in a table that has an index on the column holding them. Then things like
SELECT *
FROM table
WHERE col_name NOT IN (SELECT value_col FROM value_table);
or
SELECT *
FROM table AS t
WHERE NOT EXISTS (SELECT 1 FROM value_table WHERE value_col = t.col_name);
will be reasonably efficient no matter how many records are in value_table because that index will be used to find entries.
Plus, of course, it makes it a lot easier to re-use prepared statements because you don't have to create a new one and re-bind every value (You are using prepared statements with placeholders for these values, right, and not trying to put their contents inline into a string?) every time you add a value to the ones you need to check. You just insert it into value_table instead.
Yes, there is a limit of 999 arguments as reported in the official documentation: https://www.sqlite.org/limits.html#max_variable_number

SQLite3 on Android not adding float numbers correctly

I am having some trouble running a few simple statements on SQLite3 on Android.
For example:
SELECT 1234 + 0.001
That should return 1234.001, right? SQLite, however, returns 1234 both on the Emulator (v21) and on a real device (v19).
Considering 1234 is stored on a column called Field1, type REAL, on Table1, I have tried all the options below:
SELECT Field1 + 0.001 FROM Table1
SELECT (Field1 * 1.000) + 0.001 FROM Table1
SELECT CAST(Field1 as FLOAT) + 0.001 FROM Table1
SELECT CAST(Field1 as REAL) + 0.001 FROM Table1
SELECT Field1 + 0.001 from Table1
SELECT CAST((Field1 + 0.001) as REAL) FROM Table1
Nothing seems to work, and in every single case I am getting 1234 instead of 1234.001. I need to get 1234.001 from 1234 in a query but SQLite3 isn't being helpful.
Another thing I just found out: if "Field1" <= 999, the SELECT works as expected and I get 999.001 in the result. Anything >= 1000 gives me an integer instead.
Can you please help me how to solve this?
Actually, I found out that the problem is not what it seems. The numbers are being treated as x.001, but not shown as such. Internally, the numbers were being properly stored in binary, but not all of the decimal part was being shown. After just casting them as text, I was able to see that the decimal part was all there.
Anyhow, thank you for your time and answers.
This is an issue of precision and how numbers are stored in a computer or for that matter in sqlite3. Numbers are stored in binary format, which means that by converting a decimal number to a binary number you loose some precision (in real numbers) read more here. Now, what are your options if you want the addition to yield 1234.001 as in your example?
A) Storing the number as a string.
You can always store the values '1234' and '0.001' as VARCHARs and in JAVA code parse this values to BigDecimals and perform your additions there. For more info on parsing, check out this link. The drawback of this method is that it will consume a lot of more storage space in your database and parsing operations aren't that fast either. Before using this method, think if this drawback will impact negatively the performance of your application.
B) Establish a MAXIMUM_PRECISION and store them as INTEGERs.
By default SQLITE3 stores INTEGERs using 8 bytes. This means that the largest integer that you can store is of the order of 10^19. Now, by storing integers you dont loose precision; so we can take advantage of this. Let's say that your MAXIMUM_PRECISION is 0.001 (as in your example) then you need to multiply this number by one thousand to get a 1. So what if instead of representing 1234.001 as a real, we represent it as 1234001 an int? that way we can store the int safely in sqlite3 and make sure that the operations work properly. In your code you can later on parse the number as a String and format it to display it to an user or you can parse it to a BigDecimal in order to keep precision. Of course, this will limit you to a maximum number of the order of 10^16; again check your requirements to see if this trick will work for your app. Please note that a similar trick is used to store currency without loosing precision in sqlit3, for more info see: this link

What is the most efficient way to convert String numbers to Integers in SQLite, in order to sort by highest value?

I have two columns in my SQLite Database, name and score. I need to display the out put of all table records by score descending from highest value. I have this working at the moment but due to score being a String, of course it only goes by the first number in the string, so 30 is above 200 etc...
Here is my SQL code:
private static final String fields[] = { "name", "score", BaseColumns._ID };
Cursor data = database.query("scores", fields, null, null, null, null, "score DESC");
I have no idea how I can continue to use the above code as well as converting all of the score values to integers in order to sort by highest score first. I started to do this by converting each score value into an integer and store it in an array in order to sort them, but then I only have half of my information, so this was a bad idea, I had not thought through.
I spent about an hour reading the SQLite documentation in order to seek some way of doing this more efficiently as well as scour Stackoverflow, but to no avail. Can anyone provide advice on how I should proceed to do this?
This answer solves the problem by casting the strings as integers in the query. This is better than doing it in the program because the database is built for storing and sequencing large amounts of data, so it is much more efficient to change the query than the code.
I think the right answer is to store them as their correct type, since you only do that once when you INSERT. Why reformat every time you query and display? Makes no sense to me.

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 the 1 MB limit?
I don't think there's a hard and fast way to determine the right limit, but I looked in the CursorWindow documentation and found that copyStringToBuffer (int row, int column, CharArrayBuffer buffer) seems promising as CharArrayBuffer has a integer field called sizeCopied and the method copyStringToBuffer takes the text at the specified row and column. Maybe you can get the size from the buffer and add for each row and column you have? If you're using SQLiteCursor, you can use setWindow(CursorWindow window) to set your own window.
You can put LIMIT clause, so that rows are fetched in parts.

Sqite database insertion in android

I have an Sqlite database insertion function
ContentValues values=new ContentValues();
values.put(CardTable.KEY_USERID, card_id);
values.put("id", some id);
values.put("namr", some name);
......
getContentResolver().insert(CardManagingProvider.CONTENT_URI_DETAIL, values);
My insert query is not working. Is it because one of the values in values is a long string (Base64-encoded form of an image)? Can any one please give me any suggestions?
You can see the length limits of SQLite here.
The maximum number of bytes in a string or BLOB in SQLite is defined by the preprocessor macro SQLITE_MAX_LENGTH. The default value of this macro is 1 billion (1 thousand million or 1,000,000,000). You can raise or lower this value at compile-time using a command-line option like this:
-DSQLITE_MAX_LENGTH=123456789
The current implementation will only support a string or BLOB length up to 231-1 or 2147483647. And some built-in functions such as hex() might fail well before that point. In security-sensitive applications it is best not to try to increase the maximum string and blob length. In fact, you might do well to lower the maximum string and blob length to something more in the range of a few million if that is possible.
You can determine if your Base64 exceeds those limits, however unlikely it may be.
I would recommend, however, not storing your Base64 string in the database. The larger your database is, the longer it takes for SQL statements to process. It's considered good practice to only store the URI of your image in the database, then use that URI to locate/load your image from disk/web.

Categories

Resources