Which method should I use for a "complex" UPDATE statement? - android

I want to execute a statement such as
UPDATE myTable SET myField = myField + 1
in an Android SQLite database. (Yes, I want to increment myField for all records.)
My first idea was to use execSQL, but the documentation says:
execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
...
For UPDATE statements, use any of the following instead.
• update(String, ContentValues, String, String[])
• updateWithOnConflict(String, ContentValues, String, String[], int)
However, as far as I can see, this type of UPDATE cannot be done with the SQLiteDatabase.update method. Did I miss some clever trick to do this with SQLiteDatabase.update or is the documentation broken? (Running the above SQL with execSQL works fine, although the documentation claims otherwise.)

That method is just fine. It has to be, because the underlying C API does not distinguish those. Any statement that does not return value can be executed with execSQL.
The update* and insert* are legitimate helper methods, but the documentation would really do better if it didn't claim they must be used for all inserts/updates since they simply can't be (ever used insert into table select ...? I do that all the time!)

The execSQL will work fine in this case because it returns nothing. I am using it for the same purpose in one of my application and i never experinced issues.

Related

Android SQLite update - why whereargs?

The Android SDK documentation for SQLite provides an update method which takes as its parameters four values - table, values, whereClause, whereArgs. The first three make complete sense. However, it is not clear to me that using whereArgs with a whereClause containing ?'s as opposed to sending out a fully prepared whereClause offers any benefits - either in terms of security (there is no suggestion that this somehow helps to sanitize the SQL) or speed. So what then are the benefifts of going down that route instead of simply passing a full where string and a null whereArgs?
The docs say:
String: You may include ?s in the where clause, which will be replaced by the values from whereArgs. The values will be bound as Strings.
This is slightly misleading. No "replacement" takes place actually. Instead the ?s are variables and the whereArgs are values that are bound to those variables, and this binding happens inside the sqlite SQL program.
Using variable binding avoids issues such as SQL injection without the need to sanitize inputs.
Similar mechanism would be beneficial for performance in case you were executing the same SQL program over and over again with different values for variables. You only need to compile the SQL once. Android SQLite mechanism for that is SQLiteStatement (see the bind...() methods in its SQLiteProgram superclass).
Security is definitely an issue. If you use string concatenation, you are vulnerable to SQL Injection. Using ? and whereArgs does indeed sanitize the input so you are safe.
There is also the case of prepared statements - you compile them only once and then bind different values for each arguments placeholder. This will give you a benefit in terms of performance. You can't get that with your approach.

How to delete rows in SQLite with multiple by where args using Anko?

I hope to delete a row by _id, I hope to delete multiple rows by where args using Anko too.
I have read the article at https://github.com/Kotlin/anko/wiki/Anko-SQLite#updating-values, but I have no result, could you help me?
First off, using the update method is wrong. Deleting is not the same as updating. Updating in SQL means changing the value of one or more fields in a row. What you are looking for is the delete method
dbHelper.delete(TABLE_NAME, whereClause="Your actual where statement here", args)
The where statement follows a slightly different syntax than the regular where clauses in SQLite. This is an exception to the update method because it has a method for "regular" SQL through a builder. The delete method does not have this though, so you have to use the Anko syntax.
Essentially you can use this as a where clause:
"someRow = {someRowData} AND differentRow = {otherData}"
and in the arguments:
"someRowData" to "whatever value you want",
"otherData" to 1234
I'm not entirely sure whether or not the AND keyword will work, the syntax isn't fully documented. I assume it should because there's nothing else documented. The general SQLite syntax should be valid, and only the argument replacement (to avoid SQL injection I assume) is different

Must I use execSQL for update with expression when working with SQLite on Android?

So my question is this.
In the existing android framework is there any way to perform an UPDATE where the SET value is an expression using ContentValues?
Now what I want to achieve is an SQL update where one column is updated to the value of two other columns like so:
UPDATE myTable SET columnA = columnB + columnC WHERE rowId = 5
This works, no problem. However I can't see any way of doing this with ContentValues and the android documentation explicitly says:
void execSQL(String sql, Object[] bindArgs)
Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
...
For UPDATE statements, use any of the following instead.
update(String, ContentValues, String, String[])
updateWithOnConflict(String, ContentValues, String, String[], int)
So can it be done with the existing update methods or am I going to have to ignore the docs and go ahead with execSQL?
Ok, I'll leave this here for anyone that is as blind as me and misses the obvious:
You can go fancy and use SQliteDatabase.compileStatement(String) or as
Bob Malooga so kindly pointed out use SQLiteDatabase.rawQuery (String, String[])

SQLite case expressions in Android

Simple question: do case expressions work in Android?
I'm trying to implement a expression that checks the user value at the insert time and does some modification according to it. I know the expression is syntactically correct because it works at the SQLite prompt inside the INSERT command. However, when I try to use it in Android (using SQLiteDatabase.insert()) the expression is treated as a String. I have also tried to implement it using some of the core SQLite functions and this new expression is also treated as a String. Any thoughts why this happens?
Edit 1: rawQuery() is also not an option. The method is ignored. Here are the logcat messages that appear to be related to the method call.
The insert method treats all values as actual values, not SQL expressions.
So when you use code like this:
cv.put("Col1", "CASE X WHEN 42 THEN 'y' END");
db.insert("Tab", null, cv);
then it is assumed that the string is just a string, and that you want exactly this string to be inserted. This results in a SQL command like this:
INSERT INTO Tab(Col1) VALUES('CASE X WHEN 42 THEN ''y'' END')
If you want to do anything more complex than the simple case that insert() was designed for, you must use rawQuery instead and build the entire SQL statement by hand.
Thanks for the answers, but I solved my problem using (despite not being recommended on documentation) execSQL().

android SQLiteDatabase.insert vs executeSQL

I am working on an app which has multiple db insert/update queries and throughout the app i have used
SQLiteDatabase.insert(String table, String nullColumnHack, ContentValues values)
method for inserting any data to any table. What i mean by this is i create a ContentValues object and put all my values as key/value pair inside this object and pass it on to this this method.
contentValues.put("col1", valueCol1);
contentValues.put("col2", valueCol2);
contentValues.put("col3", valueCol3);
So just wanted to check if this way of inserting records to a sqlite table is better or is it better to use executeSQL [ From SQLinjection standpoint]. I do understand as per the documentation here
[http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#execSQL(java.lang.String)][1]
that its recommended to use insert over execSQL. But which is more prone to SQLInjections if at all one is. Any inputs/suggestions.
As suggested in the page that you linked
"Instead, you're encouraged to use insert(String, String,
ContentValues), update(String, ContentValues, String, String[]), et
al, when possible."
you should use insert() when it is possible.
To avoid SQL injection requests, you need to clearly delineate between
the SQL statement and the data it includes. The ContentProvider’s
query(), update(), and delete()methods and Activity’s managedQuery()
method all support parameterization. These methods all take the
“String[] selectionArgs” parameter, a set of values that get
substituted into the query string in place of “?” characters, in the
order the question marks appear. This provides clear separation
between the content of the SQL statement in the “selection” parameter
and the data being included. [Mobile Application Security]
So, insert() method like update() or delete() should be sql-injection free.
You should always use parametrized query methods, supported by Content Provider:
When accessing a content provider, use parameterized query methods
such as query(), update(), and delete() to avoid potential SQL
injection from untrusted sources. Note that using parameterized
methods is not sufficient if the selection argument is built by
concatenating user data prior to submitting it to the method.
reference here

Categories

Resources