I would like to display in the Log.d the current SQL query being generated by a CursorLoader in the onCreateLoader method such as:
return new CursorLoader(
getActivity(), // Parent activity context
WifiEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor
null, // No selection clause
null, // No selection arguments
WifiEntry.COLUMN_WIFI_NAME + " ASC");
I have looked at the Android docs, and in here, but no success. It is useful to debugging purposes to be able to visualize the SQL string.
Thanks!
UPDATE. I am adding the ContentProvider query method, anybody can answer how to display in the Log the resulting SQL query?
Thanks.
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
// Get readable database
SQLiteDatabase database = mDbHelper.getReadableDatabase();
// This cursor will hold the result of the query
Cursor cursor;
// Figure out if the URI matcher can match the URI to a specific code
int match = sUriMatcher.match(uri);
switch (match)
{
case WIFIS:
// For the WIFIS code, query the wifi table directly with the given
// projection, selection, selection arguments, and sort order. The cursor
// could contain multiple rows of the pets table.
cursor = database.query(WifiEntry.TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
break;
case WIFI_ID:
// For the WIFI_ID code, extract out the ID from the URI.
// the selection will be "_id=?"
selection = WifiEntry._ID + "=?";
selectionArgs = new String[] { String.valueOf(ContentUris.parseId(uri)) };
cursor = database.query(WifiEntry.TABLE_NAME, projection, selection, selectionArgs,
null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Cannot query, unknown URI " + uri);
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
// Return the cursor
return cursor;
}
Related
I am having trouble querying the my SQLiteDatabase using my custom ContentProvider. I am trying to query the database for one user using the 'user_id'. The following pieces of code which are associated with the problem are:
DBProvider.java
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder){
int match_code = myUriMatcher.match(uri);
Cursor c;
switch (match_code){
case USER_BY_ID: {
c = dbHelper.getReadableDatabase().query(
DBContract.User_Table.TABLE_NAME,
projection,
DBContract.User_Table.COLUMN_ID + "='" + ContentUris.parseId(uri) + "'",
selectionArgs,
null,
null,
sortOrder
);
break;
}
default:
throw new UnsupportedOperationException("Not yet implemented");
}
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
ProfileActivity.java
// Columns to load
String[] columns = {
DBContract.User_Table.COLUMN_NAME // String "name"
};
// A cursor is your primary interface to the query results.
Cursor cursor = getActivity().getContentResolver().query(
ContentUris.withAppendedId(DBContract.User_Table.CONTENT_URI, Long.parseLong(id)), // Table to Query
columns, // Columns for the WHERE
DBContract.User_Table.COLUMN_ID, // selection
new String[]{"1"}, // Values for the WHERE
null // Sort Args
);
The error that I am getting is:
java.lang.IllegalArgumentException: Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters.
Any help would be greatly appreciated!
Thanks
You should use:
Cursor cursor = getActivity().getContentResolver().query(
ContentUris.withAppendedId(DBContract.User_Table.CONTENT_URI, Long.parseLong(id)), // Table to Query
columns, // Columns for the WHERE
DBContract.User_Table.COLUMN_ID, // selection
null, // Values for the WHERE
null // Sort Args
);
You are using the selectionArgs parameter wrong. You don't have any ? in the selection parameter and the binding fails. More info in the documentation.
selectionArgs - You may include ?s in selection, which will be
replaced by the values from selectionArgs, in the order that they
appear in the selection. The values will be bound as Strings.
i have constructed a basic content provider that stores SMS messages for learning purposes, so far i can read(without selection args), insert, update and delete.
However i have been stumped trying to figure out how to format the selection args for the WHERE clause in my provider:
Basicly my application needs to search for a specific timestamp (in long format) and return its _id
say your database has an entry like this that your trying to access:
2|1|1410293471300|test type 1||testing|0
and the entire database looks like this:
_id|CLIENTTRXID|CREATED_AT|TYPE|MESSAGEPRIO|MESSAGE|ACCEPTED
1|1|1410293471000|test type 1||testing|0
2|1|1410293471300|test type 1||testing|0
3|1|1410293471600|test type 1||testing|0
in sql the query would be
"select _id from alerts where CREATED_AT=1410293471300;"
the code i was hoping would do the equivalent:
//normally i would get the string dynamically but to make it equal to the sql
String date = "1410293471300";
String[] selectionArgs = new String[]{ date };
Cursor cursor = getContext().getContentResolver().query(AlertContract.CONTENT_URI, null, AlertContract.Column.CREATED_AT, selectionArgs, AlertContract.DEFAULT_SORT);
seems to always produce the following error no matter what i try as selectionArgs
Exception caught﹕ Cannot bind argument at index 1 because the index is out of range. The statement has 0 parameters.
here is the query method of my contentprovider:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables( AlertContract.TABLE);
switch (sURIMatcher.match(uri)) {
case AlertContract.STATUS_DIR:
break;
case AlertContract.STATUS_ITEM:
qb.appendWhere(AlertContract.Column.ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException( "illegal uri: " + uri);
}
String orderBy = (TextUtils.isEmpty(sortOrder)) ? AlertContract.DEFAULT_SORT : sortOrder;
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
//register for uri changes
cursor.setNotificationUri(getContext().getContentResolver(), uri);
Log.d(TAG, "queried records: "+cursor.getCount());
return cursor;
}
Presumably im missing something extremely obvious, and will feel quite silly for having posted this question.
But for the moment i would very much appreciate any help, as i am quite stumped.
It looks like your issue is with your selection, rather than with your selectionArgs per se. The selection should be the whole query after the "where". Here your selection is "CREATED_AT". You need two more items to get it to work:
an =, since you want equality (you can also do other operators, of course)
a ?. This is where your selectionArgument will be inserted (each argument needs a ? in the selection, so there should be the same number of ?s in the selection as selectionArguments.
The end result should be more like "CREATED_AT = ?"
Check out the documentation and this tutorial for more info on how to correctly construct a ContentProvider query.
When you query the content provider, try the following. The selection should be AlertContract.Column.CREATED_AT + "=?"
Cursor cursor = getContext().getContentResolver().query(AlertContract.CONTENT_URI, null, AlertContract.Column.CREATED_AT + "=?", selectionArgs, AlertContract.DEFAULT_SORT);
How do I run this query in a contentprovider?
SELECT * FROM sms_data WHERE number != (SELECT DISTINCT number from test) AND time > ?
First, the query is probably wrong. Instead of number != (...) you likely want number NOT IN (...).
Assuming test is a table in your app and not in the content provider, you can perform the query in two steps:
Subquery SELECT DISTINCT number FROM test. Build a comma-separated string such as '12345','23456','45678' from the results.
Do the content provider query with selection
number NOT IN (<that comma-separated list>) AND time > ?
For a subquery you can use rawQuery() or SQLiteQueryBuilder.
Overriding onQuery method of ContentProvider, I managed to put this bunch of code that works well for me.
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (URI_MATCHER.match(uri)) {
case TABLE1:
Cursor cursor = database.query("sms_data", projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
case TABLE2:
Cursor c = database.query(true, "test", projection, selection, selectionArgs, null, null, sortOrder, null);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
case COMBINED:
String sql = "SELECT " + appendColumns(projection) +
" FROM sms_data WHERE number != IFNULL((SELECT DISTINCT number FROM test), 'abc') AND " + selection;
Cursor cur = database.rawQuery(sql, selectionArgs);
cur.setNotificationUri(getContext().getContentResolver(), uri);
return cur;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri + " Match = " + URI_MATCHER.match(uri));
}
}
Hope this works for you too.
I'm trying to retrieve a single row from my database using SQLite but for some reason my program crashes. When I search the log I get the next error:
Index -1 is requested with size of 1
I searched the web for solutions but it looks like my code is correct. I can delete a row with that parameter so I know that the position is right. It's probably how I write the query but I just don't know what's wrong with it. Can someone see why I'm doing wrong?
This is the code for the query:
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + /jokes_table");
final Uri _URI = Uri.parse(MyContentProvider.CONTENT_URI + "/2");
String positions = intent.getStringExtra("position_in_db");
Cursor cur = getBaseContext().getContentResolver().query(_URI, new String[] {"Joke","Author","Date","Status"} , MyContentProvider.ID + " = " + intent.getStringExtra("position_in_db") , null , null );
my query method :
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String a;
switch (sUriMatcher.match(uri))
{
case COLLECTION_URI_INDICATOR:
qb.setTables(TABLE_NAME);
qb.setProjectionMap(projectionMap);
break;
case SINGLE_ITEM_URI_INDICATOR:
qb.setTables(TABLE_NAME);
qb.setProjectionMap(projectionMap);
qb.appendWhere(ID);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, null);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
When I try to get all the rows by that query it works fine. The only problem is that I can't retrieve specific row. I try to change the selection with ? and try to see the string before I call the query but it won't work. Trying to reach data from the cursor by
cur.getString(getColumnIndex("Joke"));
ends the program. Can someone help me please?
What is your selection and selectionArgs??
you can try this
selection = ROW_ID_COLUMN_NAME + " =? "; // take a note on the "Space" between this statement
selectionArgs = { ROW_ID };
c = qb.query(db, projection, selection, selectionArgs, null, null, null);
// moveToFirst() method may prevent error when accessing 0 row cursor.
if (c.moveToFirst()) {
c.getString(getColumnIndex("Joke"));
}
I am using my custom ContentProvider to communicate with sqlite database. I would like to display on a list (using ListFragment), data that comes from two tables (with many to many relation). The only solution I can think of for such case is to use rawQuery. And the questions is, if it is a good practice, or should I solve this in some other way?
Example of tables:
Table A: ID, COLUMN_FROM_A
Table B: ID, COLUMN_FROM_B
Joining table AB: ID, FK_ID_A, FK_ID_B
Example of overridden query method in ContentProvider:
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
Cursor cursor = null;
int uriType = URIMatcher.match(uri);
switch (uriType) {
case TABLE_A_URI:
queryBuilder.setTables("TABLE_A");
cursor = queryBuilder.query(databaseHelper.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
break;
case TABLE_B_URI:
queryBuilder.setTables("TABLE_B");
cursor = queryBuilder.query(databaseHelper.getReadableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
break;
case TABLE_JOIN_A_B_URI:
cursor = databaseHelper.getReadableDatabase().rawQuery("select a.COLUMN_FORM_A, b.COLUMN_FROM_B from TABLE_A a, TABLE_B b, TABLE_AB ab where ab.FK_ID_A=a.ID and ab.FK_ID_B=b.ID", null);
break;
default:
throw new IllegalArgumentException("Unknown URI");
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
It's a good and common practice, very appropriate in this case.
I don't foresee any problems, we have used it in many apps.