In Android, android.database.sqlite.SQLiteStatement allows me to use prepared statements in SQLite to avoid injection attacks. Its execute method is suitable for create/update/delete operations, but there does not seem to be any method for queries that returns a cursor or the like.
Now in iOS I can create prepared statements of type sqlite3_stmt* and use them for queries, so I know this is not a limitation of SQLite. How can I perform queries with prepared statements in Android?
a prepared statement allows you to do two things
I don’t know exactly where/when Androids SQLite implementation actually uses
sqlite3_prepare(afiak notsqlite3_prepare_v2– see here) but it does use it otherwise you could not get Reached MAX size for compiled-sql statement cache errors.So if you want to query the database you have to rely on the implementation there is no way I know of to do it with
SQLiteStatement.Regarding the injection safety, every database query, insert, etc method has (sometimes alternative) versions that allow you to bind arguments.
E.g. if you want to get a
Cursorout ofCursor SQLiteDatabase#rawQuery(String sql, : fullSELECTstatment which can include?everywhereString[] selectionArgs: list of values that replace?, in order they appear)
Cursor SQLiteDatabase#query (String table, : table name, can includeJOINetcString[] columns, : list of the columns required,null=*String selection, :WHEREclause withouthWHEREcan / should include?String[] selectionArgs, : list of values that replace?, in order they appearString groupBy, :GROUP BYclause w/oGROUP BYString having, :HAVINGclause w/oHAVINGString orderBy:ORDER BYclause w/oORDER BY)Via ContentProviders – that case is slightly different since you interact with an abstract provider, not a database. There is acutally no guarantee that there is a sqlite database backing the
ContentProvider. So unless you know what columns there are / how the provider works internally you should stick to what the documentation says.Cursor ContentResolver#query(Uri uri, : an URI representing the data source (internally translated to a table)String[] projection, : list of the columns required,null=*String selection, :WHEREclause withouthWHEREcan / should include?String[] selectionArgs, : list of values that replace?, in order they appearString sortOrder:ORDER BYclause w/oORDER BY)Hint: if you want to
LIMIThere you can add it to theORDER BYclause:or depending on the implementation of the
ContentProvideradd it as a parameter to theUri:In all cases
?will be replaced by the escaped version of what you put in the bind argument.?+"hack'me"='hack''me'