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().
Related
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
My App data managed by the Content Provider using CursorLoaders is in SQLite database.
According to Veracode Static Scan report , it is prone to SQL Injections.
But according to docs,
To avoid this problem, use a selection clause that uses ? as a replaceable parameter and a separate array of selection arguments. When you do this, the user input is bound directly to the query rather than being interpreted as part of an SQL statement. Because it's not treated as SQL, the user input can't inject malicious SQL.
public Loader<Cursor> onCreateLoader(int id, Bundle b) {
return new CursorLoader(getActivity(),
NewsFeedTable.CONTENT_URI,
NewsFeedTable.PROJECTION,
"_id = ?",
new String[]{tid},
null);
}
As shown in above code, I am doing in similar way.
Also I read same in The Mobile Application Hacker's Book
If this is not sufficient measure to prevent SQL injections, how do I sanitize the sql query from the special characters?
Every read suggests using parameterized PreparedStatements.
Is it not default with Content Providers?
An alternative to SQLiteStatement is to use the query, insert, update, and delete methods on SQLiteDatabase as they offer parameterized statements via their use of string arrays.
I found this as a solution :
But then I read docs from here that
StringEscapeUtils.escapeSql
This was a misleading method, only handling the simplest of possible SQL cases. As SQL is not Lang's focus, it didn't make sense to maintain this method.
Adding the code snippet. Report points at Line 307 where SQL Injection flaw is detected:
How should I do input validation for the special characters?
Please help, to make me understand it better.
Values in selectionArgs parameters do not need to be escaped, and they must not be escaped because the escape characters would end up in the database.
There are three different cases of SQL code seen by Veracode:
values that cannot be user input (such as string literals in the source code);
values that are user input (because the come directly from, e.g., some edit box);
values that might be user input, because the tool cannot determine the source.
For marketing reasons, paid-for tools tend to inflate the problem numbers as much as possible. So Veracode reports all instances of the third case as problems.
In this case, Veracode does not know where selection comes from, so it complains. If that value is constructed by your program and never contains any user input (i.e., all user-input values are moved to ? parameters), then this is a false positive, and you must tell Veracode to shut up.
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.
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.
I would like to use SQLiteStatement in my ContentProvider instead of the rawQuery or one of the other standard methods. I think using SQLiteStatement would give a more natural, native, efficient and less error prone approach to doing queries.
The problem is that I don't see a way to generate and return a Cursor. I realize I can use "call" and return a Bundle, but that approach requires that I cache and return all selected rows at the same time - this could be huge.
I will start looking at Android source code - I presume that "query" ultimately uses SQLiteStatement and somehow generates a Cursor. However, if anyone has any pointers or knowledge of this, I would greatly appreciate your sharing.
I would like to use SQLiteStatement in my ContentProvider instead of the rawQuery or one of the other standard methods. I think using SQLiteStatement would give a more natural, native, efficient and less error prone approach to doing queries.
Quoting the documentation for SQLiteStatement:
The statement cannot return multiple rows or columns, but single value (1 x 1) result sets are supported.
I fail to see why you would bother with a ContentProvider for single row, single column results, but, hey, it's your app...
The problem is that I don't see a way to generate and return a Cursor
Create a MatrixCursor and fill in the single result.