Merge "Add calendar database upgrade code."
diff --git a/src/com/android/providers/calendar/CalendarProvider2.java b/src/com/android/providers/calendar/CalendarProvider2.java
index fc9624b..8c89ae1 100644
--- a/src/com/android/providers/calendar/CalendarProvider2.java
+++ b/src/com/android/providers/calendar/CalendarProvider2.java
@@ -73,7 +73,7 @@
private static final String TAG = "CalendarProvider2";
- private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE) || true;
+ private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean PROFILE = false;
private static final boolean MULTIPLE_ATTENDEES_PER_EVENT = true;
@@ -404,8 +404,8 @@
case EVENTS_ID:
qb.setTables(CalendarDatabaseHelper.Views.EVENTS);
qb.setProjectionMap(sEventsProjectionMap);
- qb.appendWhere("_id=");
- qb.appendWhere(uri.getPathSegments().get(1));
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getPathSegments().get(1));
+ qb.appendWhere("_id=?");
break;
case EVENT_ENTITIES:
@@ -416,8 +416,8 @@
case EVENT_ENTITIES_ID:
qb.setTables(CalendarDatabaseHelper.Views.EVENTS);
qb.setProjectionMap(sEventEntitiesProjectionMap);
- qb.appendWhere("_id=" + uri.getPathSegments().get(1));
- qb.appendWhere(uri.getPathSegments().get(1));
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getPathSegments().get(1));
+ qb.appendWhere("_id=?");
break;
case CALENDARS:
@@ -426,8 +426,8 @@
break;
case CALENDARS_ID:
qb.setTables("Calendars");
- qb.appendWhere("_id=");
- qb.appendWhere(uri.getPathSegments().get(1));
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getPathSegments().get(1));
+ qb.appendWhere("_id=?");
break;
case INSTANCES:
case INSTANCES_BY_DAY:
@@ -471,9 +471,8 @@
case ATTENDEES_ID:
qb.setTables("Attendees, Events");
qb.setProjectionMap(sAttendeesProjectionMap);
- qb.appendWhere("Attendees._id=");
- qb.appendWhere(uri.getPathSegments().get(1));
- qb.appendWhere(" AND Events._id=Attendees.event_id");
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getPathSegments().get(1));
+ qb.appendWhere("Attendees._id=? AND Events._id=Attendees.event_id");
break;
case REMINDERS:
qb.setTables("Reminders");
@@ -481,9 +480,8 @@
case REMINDERS_ID:
qb.setTables("Reminders, Events");
qb.setProjectionMap(sRemindersProjectionMap);
- qb.appendWhere("Reminders._id=");
- qb.appendWhere(uri.getLastPathSegment());
- qb.appendWhere(" AND Events._id=Reminders.event_id");
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
+ qb.appendWhere("Reminders._id=? AND Events._id=Reminders.event_id");
break;
case CALENDAR_ALERTS:
qb.setTables("CalendarAlerts, Events");
@@ -499,17 +497,16 @@
case CALENDAR_ALERTS_ID:
qb.setTables("CalendarAlerts, Events");
qb.setProjectionMap(sCalendarAlertsProjectionMap);
- qb.appendWhere("CalendarAlerts._id=");
- qb.appendWhere(uri.getLastPathSegment());
- qb.appendWhere(" AND Events._id=CalendarAlerts.event_id");
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getLastPathSegment());
+ qb.appendWhere("CalendarAlerts._id=? AND Events._id=CalendarAlerts.event_id");
break;
case EXTENDED_PROPERTIES:
qb.setTables("ExtendedProperties");
break;
case EXTENDED_PROPERTIES_ID:
qb.setTables("ExtendedProperties");
- qb.appendWhere("ExtendedProperties._id=");
- qb.appendWhere(uri.getPathSegments().get(1));
+ selectionArgs = insertSelectionArg(selectionArgs, uri.getPathSegments().get(1));
+ qb.appendWhere("ExtendedProperties._id=?");
break;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
@@ -561,18 +558,15 @@
long endMs = time.setJulianDay((int) rangeEnd + 1);
// will lock the database.
acquireInstanceRange(beginMs, endMs, true /* use minimum expansion window */);
- qb.appendWhere("startDay <= ");
- qb.appendWhere(String.valueOf(rangeEnd));
- qb.appendWhere(" AND endDay >= ");
+ qb.appendWhere("startDay<=? AND endDay>=?");
} else {
// will lock the database.
acquireInstanceRange(rangeBegin, rangeEnd, true /* use minimum expansion window */);
- qb.appendWhere("begin <= ");
- qb.appendWhere(String.valueOf(rangeEnd));
- qb.appendWhere(" AND end >= ");
+ qb.appendWhere("begin<=? AND end>=?");
}
- qb.appendWhere(String.valueOf(rangeBegin));
- return qb.query(mDb, projection, selection, null /* selectionArgs */, null /* groupBy */,
+ String selectionArgs[] = new String[] {String.valueOf(rangeEnd),
+ String.valueOf(rangeBegin)};
+ return qb.query(mDb, projection, selection, selectionArgs, null /* groupBy */,
null /* having */, sort);
}
@@ -590,11 +584,10 @@
long endMs = time.setJulianDay((int) end + 1);
acquireInstanceRange(beginMs, endMs, true);
- qb.appendWhere("startDay <= ");
- qb.appendWhere(String.valueOf(end));
- qb.appendWhere(" AND endDay >= ");
- qb.appendWhere(String.valueOf(begin));
- return qb.query(mDb, projection, selection, null /* selectionArgs */,
+ qb.appendWhere("startDay<=? AND endDay>=?");
+ String selectionArgs[] = new String[] {String.valueOf(end), String.valueOf(begin)};
+
+ return qb.query(mDb, projection, selection, selectionArgs,
Instances.START_DAY /* groupBy */, null /* having */, null);
}
@@ -760,33 +753,24 @@
String beginString = String.valueOf(begin);
String endString = String.valueOf(end);
- qb.appendWhere("(dtstart <= ");
- qb.appendWhere(endString);
- qb.appendWhere(" AND ");
- qb.appendWhere("(lastDate IS NULL OR lastDate >= ");
- qb.appendWhere(beginString);
- qb.appendWhere(")) OR (");
// grab recurrence exceptions that fall outside our expansion window but modify
// recurrences that do fall within our window. we won't insert these into the output
// set of instances, but instead will just add them to our cancellations list, so we
// can cancel the correct recurrence expansion instances.
- qb.appendWhere("originalInstanceTime IS NOT NULL ");
- qb.appendWhere("AND originalInstanceTime <= ");
- qb.appendWhere(endString);
- qb.appendWhere(" AND ");
// we don't have originalInstanceDuration or end time. for now, assume the original
// instance lasts no longer than 1 week.
// TODO: compute the originalInstanceEndTime or get this from the server.
- qb.appendWhere("originalInstanceTime >= ");
- qb.appendWhere(String.valueOf(begin - MAX_ASSUMED_DURATION));
- qb.appendWhere(")");
-
+ qb.appendWhere("(dtstart <= ? AND (lastDate IS NULL OR lastDate >= ?)) OR " +
+ "(originalInstanceTime IS NOT NULL AND originalInstanceTime <= ? AND " +
+ "originalInstanceTime >= ?)");
+ String selectionArgs[] = new String[] {endString, beginString, endString,
+ String.valueOf(begin - MAX_ASSUMED_DURATION)};
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Retrieving events to expand: " + qb.toString());
}
return qb.query(mDb, EXPAND_COLUMNS, null /* selection */,
- null /* selectionArgs */, null /* groupBy */,
+ selectionArgs, null /* groupBy */,
null /* having */, null /* sortOrder */);
}
@@ -1319,7 +1303,7 @@
}
private void setEventDirty(int eventId) {
- mDb.execSQL("UPDATE Events SET _sync_dirty=1 where _id=" + eventId);
+ mDb.execSQL("UPDATE Events SET _sync_dirty=1 where _id=?", new Integer[] {eventId});
}
/**
@@ -1460,7 +1444,7 @@
ContentValues values = new ContentValues();
values.put(Events.SELF_ATTENDEE_STATUS, status);
- db.update("Events", values, "_id="+eventId, null);
+ db.update("Events", values, "_id=?", new String[] {String.valueOf(eventId)});
}
/**
@@ -1500,7 +1484,7 @@
// For recurrence or exception, more deletion may happen below if we
// do an instance expansion. This deletion will suffice if the exception
// is moved outside the window, for instance.
- db.delete("Instances", "event_id=" + rowId, null /* selectionArgs */);
+ db.delete("Instances", "event_id=?", new String[] {String.valueOf(rowId)});
}
if (isRecurrenceEvent(values)) {
@@ -1576,19 +1560,21 @@
qb.setTables(CalendarDatabaseHelper.Views.EVENTS);
qb.setProjectionMap(sEventsProjectionMap);
+ String selectionArgs[];
if (recurrenceSyncId == null) {
- String where = "_id = " + rowId;
+ String where = "_id =?";
qb.appendWhere(where);
+ selectionArgs = new String[] {String.valueOf(rowId)};
} else {
- String where = "_sync_id = \"" + recurrenceSyncId + "\""
- + " OR originalEvent = \"" + recurrenceSyncId + "\"";
+ String where = "_sync_id = ? OR originalEvent = ?";
qb.appendWhere(where);
+ selectionArgs = new String[] {recurrenceSyncId, recurrenceSyncId};
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Retrieving events to expand: " + qb.toString());
}
- return qb.query(mDb, EXPAND_COLUMNS, null /* selection */, null /* selectionArgs */,
+ return qb.query(mDb, EXPAND_COLUMNS, null /* selection */, selectionArgs,
null /* groupBy */, null /* having */, null /* sortOrder */);
}
@@ -1613,7 +1599,7 @@
} else {
// Get the recurrence's sync id from the database
recurrenceSyncId = DatabaseUtils.stringForQuery(db, "SELECT _sync_id FROM Events"
- + " WHERE _id = " + rowId, null /* selection args */);
+ + " WHERE _id=?", new String[] {String.valueOf(rowId)});
}
// recurrenceSyncId is the _sync_id of the underlying recurrence
// If the recurrence hasn't gone to the server, it will be null.
@@ -1855,7 +1841,7 @@
}
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- return mDb.delete("Attendees", "_id=" + id, null /* selectionArgs */);
+ return mDb.delete("Attendees", "_id=?", new String[] {String.valueOf(id)});
} else {
return deleteFromTable("Attendees", uri, null /* selection */,
null /* selectionArgs */);
@@ -1876,7 +1862,7 @@
}
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- return mDb.delete("Reminders", "_id=" + id, null /* selectionArgs */);
+ return mDb.delete("Reminders", "_id=?", new String[] {String.valueOf(id)});
} else {
return deleteFromTable("Reminders", uri, null /* selection */,
null /* selectionArgs */);
@@ -1897,7 +1883,8 @@
}
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- return mDb.delete("ExtendedProperties", "_id=" + id, null /* selectionArgs */);
+ return mDb.delete("ExtendedProperties", "_id=?",
+ new String[] {String.valueOf(id)});
} else {
return deleteFromTable("ExtendedProperties", uri, null /* selection */,
null /* selectionArgs */);
@@ -1919,7 +1906,7 @@
// Note: dirty bit is not set for Alerts because it is not synced.
// It is generated from Reminders, which is synced.
long id = ContentUris.parseId(uri);
- return mDb.delete("CalendarAlerts", "_id=" + id, null /* selectionArgs */);
+ return mDb.delete("CalendarAlerts", "_id=?", new String[] {String.valueOf(id)});
}
case DELETED_EVENTS:
throw new UnsupportedOperationException("Cannot delete that URL: " + uri);
@@ -1950,8 +1937,8 @@
// Query this event to get the fields needed for deleting.
Cursor cursor = mDb.query("Events", EVENTS_PROJECTION,
- "_id=" + id,
- null /* selectionArgs */, null /* groupBy */,
+ "_id=?", new String[] {String.valueOf(id)},
+ null /* groupBy */,
null /* having */, null /* sortOrder */);
try {
if (cursor.moveToNext()) {
@@ -1978,12 +1965,12 @@
}
if (callerIsSyncAdapter) {
- mDb.delete("Events", "_id = " + id, null);
+ mDb.delete("Events", "_id=?", new String[] {String.valueOf(id)});
} else {
ContentValues values = new ContentValues();
values.put(Events.DELETED, 1);
values.put(Events._SYNC_DIRTY, 1);
- mDb.update("Events", values, "_id = " + id, null);
+ mDb.update("Events", values, "_id=?", new String[] {String.valueOf(id)});
}
}
} finally {
@@ -1992,12 +1979,13 @@
}
triggerAppWidgetUpdate(-1);
- mDb.delete("Instances", "event_id=" + id, null /* selectionArgs */);
- mDb.delete("EventsRawTimes", "event_id=" + id, null /* selectionArgs */);
- mDb.delete("Attendees", "event_id=" + id, null /* selectionArgs */);
- mDb.delete("Reminders", "event_id=" + id, null /* selectionArgs */);
- mDb.delete("CalendarAlerts", "event_id=" + id, null /* selectionArgs */);
- mDb.delete("ExtendedProperties", "event_id=" + id, null /* selectionArgs */);
+ String selectionArgs[] = new String[] {String.valueOf(id)};
+ mDb.delete("Instances", "event_id=?", selectionArgs);
+ mDb.delete("EventsRawTimes", "event_id=?", selectionArgs);
+ mDb.delete("Attendees", "event_id=?", selectionArgs);
+ mDb.delete("Reminders", "event_id=?", selectionArgs);
+ mDb.delete("CalendarAlerts", "event_id=?", selectionArgs);
+ mDb.delete("ExtendedProperties", "event_id=?", selectionArgs);
return result;
}
@@ -2019,8 +2007,8 @@
while(c.moveToNext()) {
long id = c.getLong(ID_INDEX);
long event_id = c.getLong(EVENT_ID_INDEX);
- mDb.delete(table, "_id = " + id, null /* selectionArgs */);
- mDb.update("Events", values, "_id = " + event_id, null /* selectionArgs */);
+ mDb.delete(table, "_id=?", new String[] {String.valueOf(id)});
+ mDb.update("Events", values, "_id=?", new String[] {String.valueOf(event_id)});
count++;
}
} finally {
@@ -2049,9 +2037,8 @@
while(c.moveToNext()) {
long id = c.getLong(ID_INDEX);
long event_id = c.getLong(EVENT_ID_INDEX);
- mDb.update(table, values, "_id = " + id, null /* selectionArgs */);
- mDb.update("Events", dirtyValues, "_id = " + event_id, null /* selectionArgs */);
- mDb.update(table, values, "_id = " + id, null /* selectionArgs */);
+ mDb.update(table, values, "_id=?", new String[] {String.valueOf(id)});
+ mDb.update("Events", dirtyValues, "_id=?", new String[] {String.valueOf(event_id)});
count++;
}
} finally {
@@ -2130,7 +2117,8 @@
modifyCalendarSubscription(id, syncEvents == 1);
}
- int result = mDb.update("Calendars", values, "_id="+ id, null /* selectionArgs */);
+ int result = mDb.update("Calendars", values, "_id=?",
+ new String[] {String.valueOf(id)});
return result;
}
@@ -2179,8 +2167,8 @@
return 0;
}
- int result = mDb.update("Events", updatedValues, "_id=" + id,
- null /* selectionArgs */);
+ int result = mDb.update("Events", updatedValues, "_id=?",
+ new String[] {String.valueOf(id)});
if (result > 0) {
updateEventRawTimesLocked(id, updatedValues);
updateInstancesLocked(updatedValues, id, false /* not a new event */, mDb);
@@ -2206,7 +2194,8 @@
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- return mDb.update("Attendees", values, "_id=" + id, null);
+ return mDb.update("Attendees", values, "_id=?",
+ new String[] {String.valueOf(id)});
} else {
return updateInTable("Attendees", values, uri, null /* selection */,
null /* selectionArgs */);
@@ -2219,7 +2208,8 @@
// Note: dirty bit is not set for Alerts because it is not synced.
// It is generated from Reminders, which is synced.
long id = ContentUris.parseId(uri);
- return mDb.update("CalendarAlerts", values, "_id=" + id, null /* selectionArgs */);
+ return mDb.update("CalendarAlerts", values, "_id=?",
+ new String[] {String.valueOf(id)});
}
case CALENDAR_ALERTS: {
// Note: dirty bit is not set for Alerts because it is not synced.
@@ -2232,7 +2222,8 @@
}
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- count = mDb.update("Reminders", values, "_id=" + id, null /* selectionArgs */);
+ count = mDb.update("Reminders", values, "_id=?",
+ new String[] {String.valueOf(id)});
} else {
count = updateInTable("Reminders", values, uri, null /* selection */,
null /* selectionArgs */);
@@ -2252,8 +2243,8 @@
}
if (callerIsSyncAdapter) {
long id = ContentUris.parseId(uri);
- return mDb.update("ExtendedProperties", values, "_id=" + id,
- null /* selectionArgs */);
+ return mDb.update("ExtendedProperties", values, "_id=?",
+ new String[] {String.valueOf(id)});
} else {
return updateInTable("ExtendedProperties", values, uri, null /* selection */,
null /* selectionArgs */);
@@ -2353,7 +2344,7 @@
// work. We need to keep the calendar entry in the Calendars table
// in order to know not to sync the events for that calendar from
// the server.
- String[] args = new String[] {Long.toString(id)};
+ String[] args = new String[] {String.valueOf(id)};
mDb.delete("Events", CALENDAR_ID_SELECTION, args);
// TODO: cancel any pending/ongoing syncs for this calendar.
@@ -3019,4 +3010,24 @@
return Uri.decode(value);
}
+
+ /**
+ * Inserts an argument at the beginning of the selection arg list.
+ *
+ * The {@link android.database.sqlite.SQLiteQueryBuilder}'s where clause is
+ * prepended to the user's where clause (combined with 'AND') to generate
+ * the final where close, so arguments associated with the QueryBuilder are
+ * prepended before any user selection args to keep them in the right order.
+ */
+ private String[] insertSelectionArg(String[] selectionArgs, String arg) {
+ if (selectionArgs == null) {
+ return new String[] {arg};
+ } else {
+ int newLength = selectionArgs.length + 1;
+ String[] newSelectionArgs = new String[newLength];
+ newSelectionArgs[0] = arg;
+ System.arraycopy(selectionArgs, 0, newSelectionArgs, 1, selectionArgs.length);
+ return newSelectionArgs;
+ }
+ }
}