String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER " + " = '1''";
String[] selectionArgs = String.valueOf(1);
Why do we put " = '1' " in the Selecion Query ?
and Also the Reason for String.valueOf(1);
You probably meant this:
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ?";
String[] selectionArgs = new String[]{String.valueOf(1)};
or this
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ?";
String[] selectionArgs = new String[]{"1"};
or this
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'";
String[] selectionArgs = null;
or just this
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = 1";
String[] selectionArgs = null;
All four selections have the same results: Contacts that have a phone number.
SQLite (the database type that's used on Android) doesn't support Booleans (see Datatypes in SQLite Version 3), true and false are usually stored as integers 1 and 0. So, to check if a boolean field is true you check if it has the value 1.
Code snippets #1 and #2 use a prepared statement which contains a parameter or placeholder that's replaced with the first value of the selectionArgs array (since it's the first parameter in the query). This is a technique to protect against SQL injection and it often makes your queries better readable.
selectionArgs has to be an array of String values, so the integer value 1 in snippet #1 needs to be converted to a String first (using String.valueOf(int) actually only makes sense if you pass a variable rather than a constant number).
If you don't use any variables in your select statement you can just insert all values into the statement not using placeholders and selectionArgs as in code snippets #3 and #4. Since SQLite is dynamically typed it doesn't matter if you check for equality to 1 or '1', the SQL interpreter will get it right either way.
Related
Recently I got to know that raw query in android can not prevent SQL injection and thus I decided to convert all queries in Prepared statement which is SQL injection prevention. But I don't know how to convert complex queries in Prepared Statement.
I want to convert below queries:
1.
select
*
FROM
TableName
where
(tab1col1 in(SELECT tab2Col2 FROM MasterTable where tab2col1='Y')
or tab1col2 = CV.TRUE)
order by
tab1col3, tab1col4, tab1col5,tab1col6
2.
Select
* ,count(*) as TOTAL_COUNT ,
SUM(CASE WHEN tabCol1 LIKE '%todayDate%' THEN 1 ELSE 0 END) as TOTAL_COL1_COUNT
from
TableName
group by tabCol2;
You can use rawQuery to prevent injection by passing any arguments via the selectionargs (2nd parameter).
SQL injection, wouldn't apply to either of the queries, as they are hard coded and have no user generated/supplied inputs.
e.g. your first query could be (assuming that, 'Y' and CV.TRUE are passed as parameters (i.e. user generated/supplied) for the sake of demonstration) :-
public Cursor query1raw(String indicator1,String indicator2) {
String sql = "SELECT * " +
" FROM TableName " +
" WHERE (tab1col1" +
" IN(" +
" SELECT tab2col2 " +
" FROM MasterTable " +
" WHERE tab2col1=?)" +
" OR tab1col2=?)" +
" ORDER BY tab1col3, tab1col4,tab1col5,tab1col6";
String[] args = new String[]{indicator1,indicator2};
return mDB.rawQuery(sql,args);
}
However, the convenience methods are generally recommended rather than rawQuery or execSQL when they can be used, again using bound strings via arguments, the above, using the query convenience method could be :-
public Cursor query1(String indicator1, String indicator2) {
String whereclause = "(tab1col1 IN(SELECT tab2col2 FROM MasterTable WHERE tab2col1=?) OR tab1col2=?)";
String[] whereargs = new String[] {indicator1,indicator2};
String order_columns = "tab1col3,tab1col4,tab1col5,tab1col6";
return mDB.query("TableName",null,whereclause,whereargs,null,null,order_columns);
}
You wouldn't use prepared statements themselves as they are restricted to returning single values, not a row or rows with multiple columns.
Warning not advised
However, you could, if you really wanted, use :-
public Cursor query1ps(String indicator1,String indicator2) {
String[] whereargs = new String[] {indicator1,indicator2};
SQLiteStatement stmnt = mDB.compileStatement("SELECT * " +
" FROM TableName " +
" WHERE (tab1col1" +
" IN(" +
" SELECT tab2col2 " +
" FROM MasterTable " +
" WHERE tab2col1=?)" +
" OR tab1col2=?)" +
" ORDER BY tab1col3, tab1col4,tab1col5,tab1col6");
stmnt.bindAllArgsAsStrings(whereargs);
Log.d("PREPAREDSQL",stmnt.toString());
String sql = stmnt.toString().replace("SQLiteProgram:","");
return mDB.rawQuery(sql,null);
}
As you can see all the prepared statement is doing as such, is substituting the arguments, so has little benefit over the other methods. This would also be dependant upon SQLIteProgram: remaining constant.
The only way to prevent SQL injections is to use parameters. (In some PHP APIs, the only way to get parameters is to use prepared statements, but that is not one of the warts in the Android database API.)
Just write ? for any string, and pass the values separately:
String name = ...;
String password = ...;
cursor = db.rawQuery("SELECT SomeCol FROM Users WHERE Name = ? AND Password = ?",
new String[]{ name, password });
Please not that SQL injection could happen only if you have string values that are controlled by the (potentially-hostile) user. Your queries above do not look as if this were the case.
I have to read contacts from device which are having valid phone numbers. For that right now I'm using following query.
final Uri contentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
final String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '" + ("1") + "' AND LENGTH(" + ContactsContract.CommonDataKinds.Phone.NUMBER + ") >= 10";
final String[] projection = null;
final String[] selectionArgs = null;
final String sortOrder = "upper(" + ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID + ") ASC";
Cursor phones = mContentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder);
As you can see in selection , im querying for entries with HAS_PHONE_NUMBER = 1 and length of phone number >= 10 , to avoid maximum junk contacts while retrieving from itself. It works fine , but the problem is , the saved phone numbers might have special characters like - , ( , )or a space etc.
Like +9191-91-22-22-55 , +9191-91-(22 22-55) . I need to get this string without non-digits and without country code (last 10 numbers).
For example : +9190-91-22-22-55 as 9091222255
is there any way to retrieve a string field as formatted like this in SQLite? Or is there any effective way to fulfill my requirement? Thanks in advance..
I'm trying to pull all the tracks for items i've stored in a "playlist", I have a set of android.provider.MediaStore.Audio.Media._ID values and I'm trying to build a query using the IN clause, the example below doesn't work...
String[] projection = { android.provider.MediaStore.Audio.Media.TITLE, android.provider.MediaStore.Audio.Media._ID,
android.provider.MediaStore.Audio.Media.ALBUM, android.provider.MediaStore.Audio.Media.ARTIST,
android.provider.MediaStore.Audio.Media.DURATION, android.provider.MediaStore.Audio.Media.DISPLAY_NAME,
android.provider.MediaStore.Audio.Media.ALBUM_ID, android.provider.MediaStore.Audio.Media.ARTIST_ID};
String whereString = android.provider.MediaStore.Audio.Media._ID + " IN (?)";
String[] selectionArgs = {"626,625"};
But, if I change the selecionArgs to
String[] selectionArgs = {"626"};
It does work
Should the IN clause work or am I going to have to build up a lot of OR statements (which I obviously don't want to do)
In case anyone else tried to do this the IN statement needs a matching number of '?', i.e. you can't have a single parameter that has a list of values, so this works...
String[] projection = { android.provider.MediaStore.Audio.Media.TITLE, android.provider.MediaStore.Audio.Media._ID,
android.provider.MediaStore.Audio.Media.ALBUM, android.provider.MediaStore.Audio.Media.ARTIST,
android.provider.MediaStore.Audio.Media.DURATION, android.provider.MediaStore.Audio.Media.DISPLAY_NAME,
android.provider.MediaStore.Audio.Media.ALBUM_ID, android.provider.MediaStore.Audio.Media.ARTIST_ID};
String whereString = android.provider.MediaStore.Audio.Media._ID + " IN (?,?)";
String[] selectionArgs = {"626","625"};
this is my code used which i use for making method
String item = item1.getText().toString();
item = item.toLowerCase();
String date = getDate();
edited = new Datahelper(this);
edited.open();
String returnedprice = edited.getprice(item,date);
String returneddetail = edited.getdetail(item,date);
edited.close();
price.setText(returnedprice);
details.setText(returneddetail);
and this is my code of method that i am using for getting that string but here i dont know how to use the 2nd date string so that the string price that return is from a row that contains that item and that date.. please give me the code of how to do it..
public String getprice(String item ,String date) {
// TODO Auto-generated method stub
String[] columns = new String[]{KEY_ROWID,
KEY_CATEGORY,KEY_DATE,KEY_PRICE,KEY_DETAILS};
Cursor v =ourDatabase.query(DATABASE_TABLE, columns, KEY_CATEGORY + " ='" + item
+"'",null,null, null, null);
if(v!=null){
String price = v.getString(3);
return price;
}
return null;
}
public String getdetail(String item,String date) {
// TODO Auto-generated method stub
String[] columns = new String[]{KEY_ROWID,
KEY_CATEGORY,KEY_DATE,KEY_PRICE,KEY_DETAILS};
Cursor v =ourDatabase.query(DATABASE_TABLE, columns, KEY_CATEGORY + " ='" + item +
"'",null,null, null, null);
if(v!=null){
String detail = v.getString(4);
return detail;
}
return null;
}
So probably you want to use two arguments in select query so:
You can use two methods:
rawQuery()
query()
I will give you basic example for both cases.
First:
String query = "select * from Table where someColumn = ? and someDateColumn = ?";
Cursor c = db.rawQuery(query, new String[] {textValue, dateValue});
Explanation:
So i recommend to you use ? that is called placeholder.
Each placeholder in select statement will be replaced(in same order so first placeholder will be replaced by first value in array etc.) by values from selectionArgs - it's String array declared above.
Second:
rawQuery() method was easier to understand so i started with its. Query() method is more complex and has a little bit more arguments. So
columns: represents array of columns will be selected.
selection: is in other words where clause so if your selection is
KEY_COL + " = ?" it means "where " + KEY_COL + " = ?"
selectionArgs: each placeholder will be replaced with value from this
array.
groupBy: it's multi-row (grouping) function. more
about
having: this clause is always used with group by clause here is
explanation
orderBy: is clause used for sorting rows based on one or multiple
columns
Also method has more arguments but now you don't need to care about them. If you will, Google will be your friend.
So let's back to explanation and example:
String[] columns = {KEY_COL1, KEY_COL2};
String whereClause = KEY_CATEGORY " = ? and " + KEY_DATE + " = ?";
String[] whereArgs = {"data1", "data2"};
Cursor c = db.query("Table", columns, whereClause, whereArgs, null, null, null);
So whereClause contains two arguments with placeholder for each. So first placeholder will be replaced with "data1" and second with "data2".
When query is performed, query will look like:
SELECT col1, col2 FROM Table WHERE category = 'data1' AND date = 'data2'
Note: I recommend to you have look at Android SQLite Database and ContentProvider - Tutorial.
Also i recommend to you an usage of placeholders which provide safer and much more readable and clear solutions.
You should read any SQL tutorial to find out what a WHERE clause it and how to write it.
In Android, the selection parameter is the expression in the WHERE clause.
Your query could be written like this:
c = db.query(DATABASE_TABLE, columns,
KEY_CATEGORY + " = ? AND " + KEY_DATE + " = ?",
new String[] { item, date },
null, null, null);
Hi to All I am new to Android.
I am using SQLite DataBase in my Application
meanwhile I am Written Queries using +
Like delete from tablename where value = + value;
this is my query
String delete_query = "delete from " + tableName
+ " where title = '" + title + "'";
database.execSQL(delete_query);
I want to write this Query using placeholder ?.
so that i tried
database.delete(tableName, title + "?" , new String[] {title});
instead "?" i tried (?)/('?')/'?'
but it is giving me an error....
can any one tell me how to write appropriate query using ?.....
Thanks in Advance.
Mahaveer
Make sure you have put the equal sign:-
database.delete(tableName, title + "=?" , new String[] {title});
As far as possible, try to use the less raw queries you can. Two advantages:
Query parameters will be escaped by the system (protection against SQL injection)
The code will be more readable
See the delete function of SQLiteDatabase class
public int delete (String table, String whereClause, String[]
whereArgs)
Convenience method for deleting rows in the
database.
table the table to delete from
whereClause the optional WHERE clause
to apply when deleting. Passing null will delete all rows.
Returns the number of rows affected if a whereClause is passed in, 0
otherwise. To remove all rows and get a count pass "1" as the
whereClause.
In your case:
final String where = "title=?";
final String[] args = new String[] { title };
database.delete(tableName, where, args);