How to use SQLite's built-in functions with ContentValues? - android

I want to use SQLite's built-in function datetime('now','localtime') in my Android code to save date in a database field of TEXT type. I am already able to do this in sqlite3 terminal as follows:
sqlite> INSERT INTO test (Name, NO, date) VALUES('John', 1151, datetime('now','localtime'));
sqlite> SELECT * FROM test;
John|1151|2017-06-23 17:38:29
This is fine, until I want to use the datetime() function with Android's ContentValues. I use it like this:
ContentValues values=new ContentValues();
values.put(Entry.NAME,nameString);
values.put(Entry.NO,noInt);
values.put(Entry.DATE,"datetime('now','localtime')");
/// ....
getContentResolver().insert(Entry.CONTENT_URI,values);
Then, my listview shows everything fine, but for the date's textview I exactly see the text datetime('now','localtime') instead of the date that I expected to be saved in the database e.g. 2017-06-23 17:38:29. How can I solve this problem? Is there a way I can use built-in SQLite functions with ContentValue objects for inserting data?

How can I solve this problem?
Do not use insert(). Use execSQL().
Is there a way I can use built-in SQLite functions with ContentValue objects for inserting data?
No, sorry.

Related

SQLite in Android adding quotes to start and end of datelike string

Interesting issue while using SQLite in Android. I am seeing an inconsistency in the string length and quoting of a string between what is stored in the database and the materialized value seen in Java.
We are using an ORM called SugarORM to query the DB, but I've traced the offending code to the internal android.database.sqlite.SQLiteCursor class used within SugarORM, specifically the cursor.getString(columnIndex) method.
I have a string in the database that is an ISO data string 2019-03-25T19:19:39.664Z and is stored in a VARCHAR column . I have confirmed using DB Browser for SQLite that the length of the string as its stored in the database is indeed 24 characters. SELECT LENGTH(MyStringColumn) FROM MyTable WHERE ...
When I get the value of this string via cursor.getString(columnIndex), it is returning the string "2019-03-25T19:19:39.664Z". Notice the leading and trailing quotes. Java reports to me that the string is 26 characters long.
Any value that I store in this column that is not an ISO data does not have this behavior. I tried tracing the SQLiteCursor source back, but ultimately it ends up being a Native method and that's where my skill set stops.
Can anyone explain what might be going on here? I am probably just going to write a wrapper around my queries to get rid of the quotes, but its all very perplexing. The date string is being fed to a JavaScript interpreter and causing it to fail when creating a JavaScript Date object.
If it helps, I have replicated the behavior on both my S7 physical device and a Pixel 6 emulator.
As a quick get around you could use :-
SELECT length(replace(mystringcolumn,'"','')) FROM mytable;
or before using the original SELECT use :-
UPDATE mytable SET mystringcolumn = replace(mystringcolumn,'"','');
If this doesn't fix the issue, then for some reason it is the code that retrieves the data that is at fault.
e.g. consider :-
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (mystringcolumn VARCHAR);
INSERT INTO mytable VALUES('2019-03-25T19:19:39.664Z'),('"2019-03-25T19:19:39.664Z"');
SELECT length(mystringcolumn), length(replace(mystringcolumn,'"','')) FROM mytable;
which results in :-
i.e. The 2nd row, 2nd column retrieves the appropriate value by using the replace function to strip of the quotes, if they exist.
As to why the quotes exist could depend upon either the way that the data is inserted (perhaps you have inadvertenly coded the quotes but the db being looked at isn't the actual database as copied from the App) or the way in which the data is being retrieved that for some reason adds them.
I don't believe it likely that the Cursor getString method has a bug in which the quotes are added, otherwise such an issue would likely be a recurring issue.

Android SQLite - named parameters

I'm working on Android application that uses SQLite as a local storage. I need to use parameters in sql query but all examples I have found contain unamed parameters, like so:
INSERT INTO SomeTable(ColA, ColB, ColC) VALUES (?,?,?);
I'm wondering - does SQLite on Android supports named parameters? Something like this instead of question marks..
INSERT INTO SomeTable(ColA, ColB, ColC) VALUES (#paramA, #paramB, #paramC);
SQLite itself supports this (according to the documentation https://www.sqlite.org/lang_expr.html).
Thanks in advance
The Android database API allows parameter binding only by index.
This does not prevent you from using named parameters in SQL, but you still have to use the correct index to bind them.
This is pretty much useless, except for documentation, or for reusing a parameter:
db.rawQuery("SELECT * FROM Tab WHERE A = #search OR B = #search",
new String[]{ search });
A more android SQLite specific way is to use a ContentValues for sql insert. In the example below. values is a ContentValues and it contains the column name and the value for the column. Columns not in the ContentValues are set to their default value on the insert.
id = sqlDB.insertOrThrow(RidesDatabaseHandler.TABLE_RIDES,
null, values);

Android: Failing to update row using SQL Extension function or builtin

I'm having a lot of trouble with SQLiteDatabase command. I have loaded up spatialite and enabled the extension. I want one of my values to be the output of the MakePoint function so I have a content value like this:
values.put("Location", "MakePoint(43.2, 27.345, 4326)");
When this is passed into SQLiteDatabase.Update() it's escapsed so that the resulting string ends up being "UPDATE Targets SET Location='MakePoint(43.2, 27.345, 4326)'" SQLite hates this and throws an exception.
Is there an easy way around this? Right now I'm trying to build up the string manually since I can't use Update.
SQLiteDatabase was not designed for the SpatiaLite extension.
update() supports only simple values, not generic expressions; you cannot use it to insert geographic objects.
The only way to execute your command is to build it manually an run it through execSQL().
You could write your own database wrapper object that understands SpatiaLite data types.
I figured it out. I have to do a "SELECT MakePoint(43.2, 27.345, 4326)" first and then insert that into Location.

Use of Direct Queries in SQLite?

I am currently studying SQLite and I have found that it uses various classes like ContentValues for insertion and updation... I was wondering whether I have to follow the given way or can I write a normal SQL query and use db.execSQL() method to execute them?
Will it bring any inconsistency to my database because with these all "extra" steps doesnt it stop the flow of the query and I feel it would be faster if we use a query directly.
You can do any SQL command you want with db.execSQL except select command or any other SQL command that return data (you use db.rawQuery() for this). The classes used are helper classes that make it easy for you to manipulate DBs (try inserting 100 rows with 20 columns each using ContentValues and db.execSQL and you will get the point). For small tables it will not differ much (and you will not cause inconsistecies), however, for large tables with inputs that depend on user interface or use calculations, it might be useful to have a class like ContentValues with its helper methods.
Yes you can definitely use this way like using
myDB.execSQL("INSERT INTO MyTable VALUES ('fffff', 'numb', 20)");
to insert values but only when you are using database for small queries.
Also there are some flaws using direct methods which gets removed using ContentValues
For example,try to insert a blob into the database using this method ,you will get a null bitmap while converting the retrieved data to bitmap.But when you insert using ContentValues,you will get the correct data i.e you will be able to convert that into Bitmap.

Does the Android SQLite implementation sanitize input via the SQLiteDatabase.insert() method?

The SQLiteDataBase.insert(String, String, ContentValues) convenience method takes a ContentValues object which contains all of the column values of a row to be inserted into the database. If I use the ContentValues.put() methods to build a ContentValues object to insert into the database, does either put() or insert() sanitize the input or do I have to do that myself?
Yes, this will protect you from injection. You can see in the source that insertWithOnConflict (which is called by insert) correctly uses ? place-holders in a SQLiteStatement.
%W will sanitize it with double quotes, but how much sanitation are you wanting?

Categories

Resources