Code example for SQLiteDatabase

Methods: execSQL, longForQuery, x 1

-1
     * This code is only called when upgrading from an old calendar version, 
     * so there is no problem if sync state version 3 gets used again in the 
     * future. 
     */ 
    private void upgradeSyncState(SQLiteDatabase db) {
        long version = DatabaseUtils.longForQuery(db,
                 "SELECT " + SYNC_STATE_META_VERSION_COLUMN
                 + " FROM " + Tables.SYNC_STATE_META,
                 null); 
        if (version == PRE_FROYO_SYNC_STATE_VERSION) {
            Log.i(TAG, "Upgrading calendar sync state table");
            db.execSQL("CREATE TEMPORARY TABLE state_backup(_sync_account TEXT, "
                    + "_sync_account_type TEXT, data TEXT);"); 
            db.execSQL("INSERT INTO state_backup SELECT _sync_account, _sync_account_type, data"
                    + " FROM " 
                    + Tables.SYNC_STATE
                    + " WHERE _sync_account is not NULL and _sync_account_type is not NULL;"); 
            db.execSQL("DROP TABLE " + Tables.SYNC_STATE + ";");
            mSyncState.onDatabaseOpened(db);
            db.execSQL("INSERT INTO " + Tables.SYNC_STATE + "("
                    + SyncStateContract.Columns.ACCOUNT_NAME + ","
                    + SyncStateContract.Columns.ACCOUNT_TYPE + ","
                    + SyncStateContract.Columns.DATA
                    + ") SELECT _sync_account, _sync_account_type, data from state_backup;"); 
            db.execSQL("DROP TABLE state_backup;");
        } else { 
            // Wrong version to upgrade. 
            // Don't need to do anything more here because mSyncState.onDatabaseOpened() will blow 
            // away and recreate  the database (which will result in a resync). 
            Log.w(TAG, "upgradeSyncState: current version is " + version + ", skipping upgrade.");
        } 
    } 
 
    @Override 
    public void onCreate(SQLiteDatabase db) {
        bootstrapDB(db);
    } 
 
    private void bootstrapDB(SQLiteDatabase db) {
        Log.i(TAG, "Bootstrapping database");
 
        mSyncState.createDatabase(db);
 
        createColorsTable(db);
 
        createCalendarsTable(db);
 
        createEventsTable(db);
 
        db.execSQL("CREATE TABLE " + Tables.EVENTS_RAW_TIMES + " (" +
                CalendarContract.EventsRawTimes._ID + " INTEGER PRIMARY KEY," + 
                CalendarContract.EventsRawTimes.EVENT_ID + " INTEGER NOT NULL," + 
                CalendarContract.EventsRawTimes.DTSTART_2445 + " TEXT," + 
                CalendarContract.EventsRawTimes.DTEND_2445 + " TEXT," + 
                CalendarContract.EventsRawTimes.ORIGINAL_INSTANCE_TIME_2445 + " TEXT," + 
                CalendarContract.EventsRawTimes.LAST_DATE_2445 + " TEXT," + 
                "UNIQUE (" + CalendarContract.EventsRawTimes.EVENT_ID + ")" + 
                ");"); 
 
        db.execSQL("CREATE TABLE " + Tables.INSTANCES + " (" +
                CalendarContract.Instances._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.Instances.EVENT_ID + " INTEGER," +
                CalendarContract.Instances.BEGIN + " INTEGER," +         // UTC millis
                CalendarContract.Instances.END + " INTEGER," +           // UTC millis
                CalendarContract.Instances.START_DAY + " INTEGER," +      // Julian start day
                CalendarContract.Instances.END_DAY + " INTEGER," +        // Julian end day
                CalendarContract.Instances.START_MINUTE + " INTEGER," +   // minutes from midnight
                CalendarContract.Instances.END_MINUTE + " INTEGER," +     // minutes from midnight
                "UNIQUE (" + 
                    CalendarContract.Instances.EVENT_ID + ", " +
                    CalendarContract.Instances.BEGIN + ", " +
                    CalendarContract.Instances.END + ")" +
                ");"); 
 
        db.execSQL("CREATE INDEX instancesStartDayIndex ON " + Tables.INSTANCES + " (" +
                CalendarContract.Instances.START_DAY +
                ");"); 
 
        createCalendarMetaDataTable(db);
 
        createCalendarCacheTable(db, null);
 
        db.execSQL("CREATE TABLE " + Tables.ATTENDEES + " (" +
                CalendarContract.Attendees._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.Attendees.EVENT_ID + " INTEGER," +
                CalendarContract.Attendees.ATTENDEE_NAME + " TEXT," +
                CalendarContract.Attendees.ATTENDEE_EMAIL + " TEXT," +
                CalendarContract.Attendees.ATTENDEE_STATUS + " INTEGER," +
                CalendarContract.Attendees.ATTENDEE_RELATIONSHIP + " INTEGER," +
                CalendarContract.Attendees.ATTENDEE_TYPE + " INTEGER," +
                CalendarContract.Attendees.ATTENDEE_IDENTITY + " TEXT," +
                CalendarContract.Attendees.ATTENDEE_ID_NAMESPACE + " TEXT" +
                ");"); 
 
        db.execSQL("CREATE INDEX attendeesEventIdIndex ON " + Tables.ATTENDEES + " (" +
                CalendarContract.Attendees.EVENT_ID +
                ");"); 
 
        db.execSQL("CREATE TABLE " + Tables.REMINDERS + " (" +
                CalendarContract.Reminders._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.Reminders.EVENT_ID + " INTEGER," +
                CalendarContract.Reminders.MINUTES + " INTEGER," +
                CalendarContract.Reminders.METHOD + " INTEGER NOT NULL" +
                " DEFAULT " + CalendarContract.Reminders.METHOD_DEFAULT +
                ");"); 
 
        db.execSQL("CREATE INDEX remindersEventIdIndex ON " + Tables.REMINDERS + " (" +
                CalendarContract.Reminders.EVENT_ID +
                ");"); 
 
         // This table stores the Calendar notifications that have gone off. 
        db.execSQL("CREATE TABLE " + Tables.CALENDAR_ALERTS + " (" +
                CalendarContract.CalendarAlerts._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.CalendarAlerts.EVENT_ID + " INTEGER," +
                CalendarContract.CalendarAlerts.BEGIN + " INTEGER NOT NULL," +      // UTC millis
                CalendarContract.CalendarAlerts.END + " INTEGER NOT NULL," +        // UTC millis
                CalendarContract.CalendarAlerts.ALARM_TIME + " INTEGER NOT NULL," + // UTC millis
                // UTC millis 
                CalendarContract.CalendarAlerts.CREATION_TIME + " INTEGER NOT NULL DEFAULT 0," +
                // UTC millis 
                CalendarContract.CalendarAlerts.RECEIVED_TIME + " INTEGER NOT NULL DEFAULT 0," +
                // UTC millis 
                CalendarContract.CalendarAlerts.NOTIFY_TIME + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.CalendarAlerts.STATE + " INTEGER NOT NULL," +
                CalendarContract.CalendarAlerts.MINUTES + " INTEGER," +
                "UNIQUE (" + 
                    CalendarContract.CalendarAlerts.ALARM_TIME + ", " +
                    CalendarContract.CalendarAlerts.BEGIN + ", " +
                    CalendarContract.CalendarAlerts.EVENT_ID + ")" +
                ");"); 
 
        db.execSQL("CREATE INDEX calendarAlertsEventIdIndex ON " + Tables.CALENDAR_ALERTS + " (" +
                CalendarContract.CalendarAlerts.EVENT_ID +
                ");"); 
 
        db.execSQL("CREATE TABLE " + Tables.EXTENDED_PROPERTIES + " (" +
                CalendarContract.ExtendedProperties._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.ExtendedProperties.EVENT_ID + " INTEGER," +
                CalendarContract.ExtendedProperties.NAME + " TEXT," +
                CalendarContract.ExtendedProperties.VALUE + " TEXT" +
                ");"); 
 
        db.execSQL("CREATE INDEX extendedPropertiesEventIdIndex ON " + Tables.EXTENDED_PROPERTIES
                + " (" + 
                CalendarContract.ExtendedProperties.EVENT_ID +
                ");"); 
 
        createEventsView(db);
 
        // Trigger to remove data tied to an event when we delete that event. 
        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
                "BEGIN " + 
                EVENTS_CLEANUP_TRIGGER_SQL +
                "END"); 
 
        // Triggers to update the color stored in an event or a calendar when 
        // the color_index is changed. 
        createColorsTriggers(db);
 
        // Trigger to update exceptions when an original event updates its 
        // _sync_id 
        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
 
        scheduleSync(null /* all accounts */, false, null); 
    } 
 
    private void createEventsTable(SQLiteDatabase db) {
        // IMPORTANT: when adding new columns, be sure to update ALLOWED_IN_EXCEPTION and 
        // DONT_CLONE_INTO_EXCEPTION in CalendarProvider2. 
        // 
        // TODO: do we need both dtend and duration? 
        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS 
        db.execSQL("CREATE TABLE " + Tables.EVENTS + " (" +
                CalendarContract.Events._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                CalendarContract.Events._SYNC_ID + " TEXT," +
                CalendarContract.Events.DIRTY + " INTEGER," +
                CalendarContract.Events.MUTATORS + " TEXT," + 
                CalendarContract.Events.LAST_SYNCED + " INTEGER DEFAULT 0," +
                CalendarContract.Events.CALENDAR_ID + " INTEGER NOT NULL," +
                CalendarContract.Events.TITLE + " TEXT," +
                CalendarContract.Events.EVENT_LOCATION + " TEXT," +
                CalendarContract.Events.DESCRIPTION + " TEXT," +
                CalendarContract.Events.EVENT_COLOR + " INTEGER," +
                CalendarContract.Events.EVENT_COLOR_KEY + " TEXT," +
                CalendarContract.Events.STATUS + " INTEGER," +
                CalendarContract.Events.SELF_ATTENDEE_STATUS + " INTEGER NOT NULL DEFAULT 0," +
                // dtstart in millis since epoch 
                CalendarContract.Events.DTSTART + " INTEGER," +
                // dtend in millis since epoch 
                CalendarContract.Events.DTEND + " INTEGER," +
                // timezone for event 
                CalendarContract.Events.EVENT_TIMEZONE + " TEXT," +
                CalendarContract.Events.DURATION + " TEXT," +
                CalendarContract.Events.ALL_DAY + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.ACCESS_LEVEL + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.AVAILABILITY + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.HAS_ALARM + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.HAS_EXTENDED_PROPERTIES + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.RRULE + " TEXT," +
                CalendarContract.Events.RDATE + " TEXT," +
                CalendarContract.Events.EXRULE + " TEXT," +
                CalendarContract.Events.EXDATE + " TEXT," +
                CalendarContract.Events.ORIGINAL_ID + " INTEGER," +
                // ORIGINAL_SYNC_ID is the _sync_id of recurring event 
                CalendarContract.Events.ORIGINAL_SYNC_ID + " TEXT," +
                // originalInstanceTime is in millis since epoch 
                CalendarContract.Events.ORIGINAL_INSTANCE_TIME + " INTEGER," +
                CalendarContract.Events.ORIGINAL_ALL_DAY + " INTEGER," +
                // lastDate is in millis since epoch 
                CalendarContract.Events.LAST_DATE + " INTEGER," +
                CalendarContract.Events.HAS_ATTENDEE_DATA + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.GUESTS_CAN_MODIFY + " INTEGER NOT NULL DEFAULT 0," +
                CalendarContract.Events.GUESTS_CAN_INVITE_OTHERS + " INTEGER NOT NULL DEFAULT 1," +
                CalendarContract.Events.GUESTS_CAN_SEE_GUESTS + " INTEGER NOT NULL DEFAULT 1," +
                CalendarContract.Events.ORGANIZER + " STRING," +
                CalendarContract.Events.IS_ORGANIZER + " INTEGER," +
                CalendarContract.Events.DELETED + " INTEGER NOT NULL DEFAULT 0," +
                // timezone for event with allDay events are in local timezone 
                CalendarContract.Events.EVENT_END_TIMEZONE + " TEXT," +
                CalendarContract.Events.CUSTOM_APP_PACKAGE + " TEXT," +
                CalendarContract.Events.CUSTOM_APP_URI + " TEXT," +
                CalendarContract.Events.UID_2445 + " TEXT," +
                // SYNC_DATAX columns are available for use by sync adapters 
                CalendarContract.Events.SYNC_DATA1 + " TEXT," +
                CalendarContract.Events.SYNC_DATA2 + " TEXT," +
                CalendarContract.Events.SYNC_DATA3 + " TEXT," +
                CalendarContract.Events.SYNC_DATA4 + " TEXT," +
                CalendarContract.Events.SYNC_DATA5 + " TEXT," +
                CalendarContract.Events.SYNC_DATA6 + " TEXT," +
                CalendarContract.Events.SYNC_DATA7 + " TEXT," +
                CalendarContract.Events.SYNC_DATA8 + " TEXT," +
                CalendarContract.Events.SYNC_DATA9 + " TEXT," +
                CalendarContract.Events.SYNC_DATA10 + " TEXT" + ");");
 
        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS 
 
        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON " + Tables.EVENTS + " ("
                + CalendarContract.Events.CALENDAR_ID + ");");
    } 
 
    private void createEventsTable307(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Events ("
                + "_id INTEGER PRIMARY KEY AUTOINCREMENT," 
                + "_sync_id TEXT," 
                + "dirty INTEGER," 
                + "lastSynced INTEGER DEFAULT 0," 
                + "calendar_id INTEGER NOT NULL," 
                + "title TEXT," 
                + "eventLocation TEXT," 
                + "description TEXT," 
                + "eventColor INTEGER," 
                + "eventStatus INTEGER," 
                + "selfAttendeeStatus INTEGER NOT NULL DEFAULT 0," 
                // dtstart in millis since epoch 
                + "dtstart INTEGER," 
                // dtend in millis since epoch 
                + "dtend INTEGER," 
                // timezone for event 
                + "eventTimezone TEXT," 
                + "duration TEXT," 
                + "allDay INTEGER NOT NULL DEFAULT 0," 
                + "accessLevel INTEGER NOT NULL DEFAULT 0," 
                + "availability INTEGER NOT NULL DEFAULT 0," 
                + "hasAlarm INTEGER NOT NULL DEFAULT 0," 
                + "hasExtendedProperties INTEGER NOT NULL DEFAULT 0," 
                + "rrule TEXT," 
                + "rdate TEXT," 
                + "exrule TEXT," 
                + "exdate TEXT," 
                + "original_id INTEGER," 
                // ORIGINAL_SYNC_ID is the _sync_id of recurring event 
                + "original_sync_id TEXT," 
                // originalInstanceTime is in millis since epoch 
                + "originalInstanceTime INTEGER," 
                + "originalAllDay INTEGER," 
                // lastDate is in millis since epoch 
                + "lastDate INTEGER," 
                + "hasAttendeeData INTEGER NOT NULL DEFAULT 0," 
                + "guestsCanModify INTEGER NOT NULL DEFAULT 0," 
                + "guestsCanInviteOthers INTEGER NOT NULL DEFAULT 1," 
                + "guestsCanSeeGuests INTEGER NOT NULL DEFAULT 1," 
                + "organizer STRING," 
                + "deleted INTEGER NOT NULL DEFAULT 0," 
                // timezone for event with allDay events are in local timezone 
                + "eventEndTimezone TEXT," 
                // SYNC_DATAX columns are available for use by sync adapters 
                + "sync_data1 TEXT," 
                + "sync_data2 TEXT," 
                + "sync_data3 TEXT," 
                + "sync_data4 TEXT," 
                + "sync_data5 TEXT," 
                + "sync_data6 TEXT," 
                + "sync_data7 TEXT," 
                + "sync_data8 TEXT," 
                + "sync_data9 TEXT," 
                + "sync_data10 TEXT);"); 
 
        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS 
 
        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON Events (calendar_id);");
    } 
 
    // TODO Remove this method after merging all ICS upgrades 
    private void createEventsTable300(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Events (" +
                "_id INTEGER PRIMARY KEY," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                // sync time in UTC 
                "_sync_time TEXT,"  + 
                "_sync_local_id INTEGER," + 
                "dirty INTEGER," + 
                // sync mark to filter out new rows 
                "_sync_mark INTEGER," + 
                "calendar_id INTEGER NOT NULL," + 
                "htmlUri TEXT," + 
                "title TEXT," + 
                "eventLocation TEXT," + 
                "description TEXT," + 
                "eventStatus INTEGER," + 
                "selfAttendeeStatus INTEGER NOT NULL DEFAULT 0," + 
                "commentsUri TEXT," + 
                // dtstart in millis since epoch 
                "dtstart INTEGER," + 
                // dtend in millis since epoch 
                "dtend INTEGER," + 
                // timezone for event 
                "eventTimezone TEXT," + 
                "duration TEXT," + 
                "allDay INTEGER NOT NULL DEFAULT 0," + 
                "accessLevel INTEGER NOT NULL DEFAULT 0," + 
                "availability INTEGER NOT NULL DEFAULT 0," + 
                "hasAlarm INTEGER NOT NULL DEFAULT 0," + 
                "hasExtendedProperties INTEGER NOT NULL DEFAULT 0," + 
                "rrule TEXT," + 
                "rdate TEXT," + 
                "exrule TEXT," + 
                "exdate TEXT," + 
                // originalEvent is the _sync_id of recurring event 
                "original_sync_id TEXT," + 
                // originalInstanceTime is in millis since epoch 
                "originalInstanceTime INTEGER," + 
                "originalAllDay INTEGER," + 
                // lastDate is in millis since epoch 
                "lastDate INTEGER," + 
                "hasAttendeeData INTEGER NOT NULL DEFAULT 0," + 
                "guestsCanModify INTEGER NOT NULL DEFAULT 0," + 
                "guestsCanInviteOthers INTEGER NOT NULL DEFAULT 1," + 
                "guestsCanSeeGuests INTEGER NOT NULL DEFAULT 1," + 
                "organizer STRING," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                // timezone for event with allDay events are in local timezone 
                "eventEndTimezone TEXT," + 
                // syncAdapterData is available for use by sync adapters 
                "sync_data1 TEXT);"); 
 
        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON Events (calendar_id);");
    } 
 
    private void createCalendarsTable303(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
                "_id INTEGER PRIMARY KEY," + 
                "account_name TEXT," + 
                "account_type TEXT," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                "_sync_time TEXT," +  // UTC 
                "dirty INTEGER," + 
                "name TEXT," + 
                "displayName TEXT," + 
                "calendar_color INTEGER," + 
                "access_level INTEGER," + 
                "visible INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "calendar_location TEXT," + 
                "calendar_timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," + 
                "canModifyTimeZone INTEGER DEFAULT 1," + 
                "maxReminders INTEGER DEFAULT 5," + 
                "allowedReminders TEXT DEFAULT '0,1'," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "cal_sync1 TEXT," + 
                "cal_sync2 TEXT," + 
                "cal_sync3 TEXT," + 
                "cal_sync4 TEXT," + 
                "cal_sync5 TEXT," + 
                "cal_sync6 TEXT" + 
                ");"); 
 
        // Trigger to remove a calendar's events when we delete the calendar 
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
                "BEGIN " + 
                CALENDAR_CLEANUP_TRIGGER_SQL +
                "END"); 
    } 
 
    private void createColorsTable(SQLiteDatabase db) {
 
        db.execSQL("CREATE TABLE " + Tables.COLORS + " (" +
                CalendarContract.Colors._ID + " INTEGER PRIMARY KEY," +
                CalendarContract.Colors.ACCOUNT_NAME + " TEXT NOT NULL," +
                CalendarContract.Colors.ACCOUNT_TYPE + " TEXT NOT NULL," +
                CalendarContract.Colors.DATA + " TEXT," +
                CalendarContract.Colors.COLOR_TYPE + " INTEGER NOT NULL," +
                CalendarContract.Colors.COLOR_KEY + " TEXT NOT NULL," +
                CalendarContract.Colors.COLOR + " INTEGER NOT NULL" +
                ");"); 
    } 
 
    public void createColorsTriggers(SQLiteDatabase db) {
        db.execSQL(CREATE_EVENT_COLOR_UPDATE_TRIGGER);
        db.execSQL(CREATE_CALENDAR_COLOR_UPDATE_TRIGGER);
    } 
 
    private void createCalendarsTable(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
                Calendars._ID + " INTEGER PRIMARY KEY," +
                Calendars.ACCOUNT_NAME + " TEXT," +
                Calendars.ACCOUNT_TYPE + " TEXT," +
                Calendars._SYNC_ID + " TEXT," +
                Calendars.DIRTY + " INTEGER," +
                Calendars.MUTATORS + " TEXT," + 
                Calendars.NAME + " TEXT," +
                Calendars.CALENDAR_DISPLAY_NAME + " TEXT," +
                Calendars.CALENDAR_COLOR + " INTEGER," +
                Calendars.CALENDAR_COLOR_KEY + " TEXT," +
                Calendars.CALENDAR_ACCESS_LEVEL + " INTEGER," +
                Calendars.VISIBLE + " INTEGER NOT NULL DEFAULT 1," +
                Calendars.SYNC_EVENTS + " INTEGER NOT NULL DEFAULT 0," +
                Calendars.CALENDAR_LOCATION + " TEXT," +
                Calendars.CALENDAR_TIME_ZONE + " TEXT," +
                Calendars.OWNER_ACCOUNT + " TEXT, " +
                Calendars.IS_PRIMARY + " INTEGER, " +
                Calendars.CAN_ORGANIZER_RESPOND + " INTEGER NOT NULL DEFAULT 1," +
                Calendars.CAN_MODIFY_TIME_ZONE + " INTEGER DEFAULT 1," +
                Calendars.CAN_PARTIALLY_UPDATE + " INTEGER DEFAULT 0," +
                Calendars.MAX_REMINDERS + " INTEGER DEFAULT 5," +
                Calendars.ALLOWED_REMINDERS + " TEXT DEFAULT '0,1'," +
                Calendars.ALLOWED_AVAILABILITY + " TEXT DEFAULT '0,1'," +
                Calendars.ALLOWED_ATTENDEE_TYPES + " TEXT DEFAULT '0,1,2'," +
                Calendars.DELETED + " INTEGER NOT NULL DEFAULT 0," +
                Calendars.CAL_SYNC1 + " TEXT," +
                Calendars.CAL_SYNC2 + " TEXT," +
                Calendars.CAL_SYNC3 + " TEXT," +
                Calendars.CAL_SYNC4 + " TEXT," +
                Calendars.CAL_SYNC5 + " TEXT," +
                Calendars.CAL_SYNC6 + " TEXT," +
                Calendars.CAL_SYNC7 + " TEXT," +
                Calendars.CAL_SYNC8 + " TEXT," +
                Calendars.CAL_SYNC9 + " TEXT," +
                Calendars.CAL_SYNC10 + " TEXT" +
                ");"); 
 
        // Trigger to remove a calendar's events when we delete the calendar 
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
                "BEGIN " + 
                CALENDAR_CLEANUP_TRIGGER_SQL +
                "END"); 
    } 
 
    private void createCalendarsTable305(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Calendars (" +
                "_id INTEGER PRIMARY KEY," + 
                "account_name TEXT," + 
                "account_type TEXT," + 
                "_sync_id TEXT," + 
                "dirty INTEGER," + 
                "name TEXT," + 
                "calendar_displayName TEXT," + 
                "calendar_color INTEGER," + 
                "calendar_access_level INTEGER," + 
                "visible INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "calendar_location TEXT," + 
                "calendar_timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," + 
                "canModifyTimeZone INTEGER DEFAULT 1," + 
                "canPartiallyUpdate INTEGER DEFAULT 0," + 
                "maxReminders INTEGER DEFAULT 5," + 
                "allowedReminders TEXT DEFAULT '0,1'," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "cal_sync1 TEXT," + 
                "cal_sync2 TEXT," + 
                "cal_sync3 TEXT," + 
                "cal_sync4 TEXT," + 
                "cal_sync5 TEXT," + 
                "cal_sync6 TEXT," + 
                "cal_sync7 TEXT," + 
                "cal_sync8 TEXT," + 
                "cal_sync9 TEXT," + 
                "cal_sync10 TEXT" + 
                ");"); 
 
        // Trigger to remove a calendar's events when we delete the calendar 
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
                "BEGIN " + 
                "DELETE FROM Events WHERE calendar_id=old._id;" + 
                "END"); 
    } 
 
    private void createCalendarsTable300(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
                "_id INTEGER PRIMARY KEY," + 
                "account_name TEXT," + 
                "account_type TEXT," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                "_sync_time TEXT," +  // UTC 
                "dirty INTEGER," + 
                "name TEXT," + 
                "displayName TEXT," + 
                "calendar_color INTEGER," + 
                "access_level INTEGER," + 
                "visible INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "calendar_location TEXT," + 
                "calendar_timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," + 
                "canModifyTimeZone INTEGER DEFAULT 1," + 
                "maxReminders INTEGER DEFAULT 5," + 
                "allowedReminders TEXT DEFAULT '0,1,2'," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "sync1 TEXT," + 
                "sync2 TEXT," + 
                "sync3 TEXT," + 
                "sync4 TEXT," + 
                "sync5 TEXT," + 
                "sync6 TEXT" + 
                ");"); 
 
        // Trigger to remove a calendar's events when we delete the calendar 
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
                "BEGIN " + 
                CALENDAR_CLEANUP_TRIGGER_SQL +
                "END"); 
    } 
 
    private void createCalendarsTable205(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Calendars (" +
                "_id INTEGER PRIMARY KEY," + 
                "_sync_account TEXT," + 
                "_sync_account_type TEXT," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                "_sync_time TEXT," +  // UTC 
                "_sync_dirty INTEGER," + 
                "name TEXT," + 
                "displayName TEXT," + 
                "color INTEGER," + 
                "access_level INTEGER," + 
                "visible INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "location TEXT," + 
                "timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," + 
                "canModifyTimeZone INTEGER DEFAULT 1, " + 
                "maxReminders INTEGER DEFAULT 5," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "sync1 TEXT," + 
                "sync2 TEXT," + 
                "sync3 TEXT," + 
                "sync4 TEXT," + 
                "sync5 TEXT," + 
                "sync6 TEXT" + 
                ");"); 
 
        createCalendarsCleanup200(db);
    } 
 
    private void createCalendarsTable202(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Calendars (" +
                "_id INTEGER PRIMARY KEY," + 
                "_sync_account TEXT," + 
                "_sync_account_type TEXT," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                "_sync_time TEXT," +  // UTC 
                "_sync_local_id INTEGER," + 
                "_sync_dirty INTEGER," + 
                "_sync_mark INTEGER," + // Used to filter out new rows 
                "name TEXT," + 
                "displayName TEXT," + 
                "color INTEGER," + 
                "access_level INTEGER," + 
                "selected INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "location TEXT," + 
                "timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "organizerCanRespond INTEGER NOT NULL DEFAULT 1," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "sync1 TEXT," + 
                "sync2 TEXT," + 
                "sync3 TEXT," + 
                "sync4 TEXT," + 
                "sync5 TEXT" + 
                ");"); 
 
        createCalendarsCleanup200(db);
    } 
 
    private void createCalendarsTable200(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE Calendars (" +
                "_id INTEGER PRIMARY KEY," + 
                "_sync_account TEXT," + 
                "_sync_account_type TEXT," + 
                "_sync_id TEXT," + 
                "_sync_version TEXT," + 
                "_sync_time TEXT," +  // UTC 
                "_sync_local_id INTEGER," + 
                "_sync_dirty INTEGER," + 
                "_sync_mark INTEGER," + // Used to filter out new rows 
                "name TEXT," + 
                "displayName TEXT," + 
                "hidden INTEGER NOT NULL DEFAULT 0," + 
                "color INTEGER," + 
                "access_level INTEGER," + 
                "selected INTEGER NOT NULL DEFAULT 1," + 
                "sync_events INTEGER NOT NULL DEFAULT 0," + 
                "location TEXT," + 
                "timezone TEXT," + 
                "ownerAccount TEXT, " + 
                "organizerCanRespond INTEGER NOT NULL DEFAULT 1," + 
                "deleted INTEGER NOT NULL DEFAULT 0," + 
                "sync1 TEXT," + 
                "sync2 TEXT," + 
                "sync3 TEXT" + 
                ");"); 
 
        createCalendarsCleanup200(db);
    } 
 
    /** Trigger to remove a calendar's events when we delete the calendar */ 
    private void createCalendarsCleanup200(SQLiteDatabase db) {
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
                "BEGIN " + 
                "DELETE FROM Events WHERE calendar_id=old._id;" + 
                "END"); 
    } 
 
    private void createCalendarMetaDataTable(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.CALENDAR_META_DATA + " (" +
                CalendarContract.CalendarMetaData._ID + " INTEGER PRIMARY KEY," + 
                CalendarContract.CalendarMetaData.LOCAL_TIMEZONE + " TEXT," + 
                CalendarContract.CalendarMetaData.MIN_INSTANCE + " INTEGER," +      // UTC millis 
                CalendarContract.CalendarMetaData.MAX_INSTANCE + " INTEGER" +       // UTC millis 
                ");"); 
    } 
 
    private void createCalendarMetaDataTable59(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE CalendarMetaData (" +
                "_id INTEGER PRIMARY KEY," + 
                "localTimezone TEXT," + 
                "minInstance INTEGER," +      // UTC millis 
                "maxInstance INTEGER" +       // UTC millis 
                ");"); 
    } 
 
    private void createCalendarCacheTable(SQLiteDatabase db, String oldTimezoneDbVersion) {
        // This is a hack because versioning skipped version number 61 of schema 
        // TODO after version 70 this can be removed 
        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDAR_CACHE + ";");
 
        // IF NOT EXISTS should be normal pattern for table creation 
        db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.CALENDAR_CACHE + " (" +
                CalendarCache.COLUMN_NAME_ID + " INTEGER PRIMARY KEY," + 
                CalendarCache.COLUMN_NAME_KEY + " TEXT NOT NULL," + 
                CalendarCache.COLUMN_NAME_VALUE + " TEXT" + 
                ");"); 
 
        initCalendarCacheTable(db, oldTimezoneDbVersion);
        updateCalendarCacheTable(db);
    } 
 
    private void initCalendarCacheTable(SQLiteDatabase db, String oldTimezoneDbVersion) {
        String timezoneDbVersion = (oldTimezoneDbVersion != null) ?
                oldTimezoneDbVersion : CalendarCache.DEFAULT_TIMEZONE_DATABASE_VERSION;
 
        // Set the default timezone database version 
        db.execSQL("INSERT OR REPLACE INTO " + Tables.CALENDAR_CACHE +
                " (" + CalendarCache.COLUMN_NAME_ID + ", " + 
                CalendarCache.COLUMN_NAME_KEY + ", " + 
                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" + 
                CalendarCache.KEY_TIMEZONE_DATABASE_VERSION.hashCode() + "," + 
                "'" + CalendarCache.KEY_TIMEZONE_DATABASE_VERSION + "'," + 
                "'" + timezoneDbVersion + "'" +
                ");"); 
    } 
 
    private void updateCalendarCacheTable(SQLiteDatabase db) {
        // Define the default timezone type for Instances timezone management 
        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
                " (" + CalendarCache.COLUMN_NAME_ID + ", " + 
                CalendarCache.COLUMN_NAME_KEY + ", " + 
                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" + 
                CalendarCache.KEY_TIMEZONE_TYPE.hashCode() + "," + 
                "'" + CalendarCache.KEY_TIMEZONE_TYPE + "',"  + 
                "'" + CalendarCache.TIMEZONE_TYPE_AUTO + "'" + 
                ");"); 
 
        String defaultTimezone = TimeZone.getDefault().getID();
 
        // Define the default timezone for Instances 
        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
                " (" + CalendarCache.COLUMN_NAME_ID + ", " + 
                CalendarCache.COLUMN_NAME_KEY + ", " + 
                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" + 
                CalendarCache.KEY_TIMEZONE_INSTANCES.hashCode() + "," + 
                "'" + CalendarCache.KEY_TIMEZONE_INSTANCES + "',"  + 
                "'" + defaultTimezone + "'" +
                ");"); 
 
        // Define the default previous timezone for Instances 
        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
                " (" + CalendarCache.COLUMN_NAME_ID + ", " + 
                CalendarCache.COLUMN_NAME_KEY + ", " + 
                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" + 
                CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS.hashCode() + "," + 
                "'" + CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS + "',"  + 
                "'" + defaultTimezone + "'" +
                ");"); 
    } 
 
    private void initCalendarCacheTable203(SQLiteDatabase db, String oldTimezoneDbVersion) {
        String timezoneDbVersion = (oldTimezoneDbVersion != null) ?
                oldTimezoneDbVersion : "2009s";
 
        // Set the default timezone database version 
        db.execSQL("INSERT OR REPLACE INTO CalendarCache" +
                " (_id, " + 
                "key, " + 
                "value) VALUES (" + 
                "timezoneDatabaseVersion".hashCode() + "," +
                "'timezoneDatabaseVersion',"  + 
                "'" + timezoneDbVersion + "'" +
                ");"); 
    } 
 
    private void updateCalendarCacheTableTo203(SQLiteDatabase db) {
        // Define the default timezone type for Instances timezone management 
        db.execSQL("INSERT INTO CalendarCache" +
                " (_id, key, value) VALUES (" + 
                "timezoneType".hashCode() + "," +
                "'timezoneType',"  + 
                "'auto'" + 
                ");"); 
 
        String defaultTimezone = TimeZone.getDefault().getID();
 
        // Define the default timezone for Instances 
        db.execSQL("INSERT INTO CalendarCache" +
                " (_id, key, value) VALUES (" + 
                "timezoneInstances".hashCode() + "," +
                "'timezoneInstances',"  + 
                "'" + defaultTimezone + "'" +
                ");"); 
 
        // Define the default previous timezone for Instances 
        db.execSQL("INSERT INTO CalendarCache" +
                " (_id, key, value) VALUES (" + 
                "timezoneInstancesPrevious".hashCode() + "," +
                "'timezoneInstancesPrevious',"  + 
                "'" + defaultTimezone + "'" +
                ");"); 
    } 
 
    /** 
     * Removes orphaned data from the database.  Specifically: 
     * <ul> 
     * <li>Attendees with an event_id for a nonexistent Event 
     * <li>Reminders with an event_id for a nonexistent Event 
     * </ul> 
     */ 
    static void removeOrphans(SQLiteDatabase db) {
        if (false) {        // debug mode 
            String SELECT_ATTENDEES_ORPHANS = "SELECT " +
                    Attendees._ID + ", " + Attendees.EVENT_ID + " FROM " + Tables.ATTENDEES +
                    " WHERE " + WHERE_ATTENDEES_ORPHANS;
 
            Cursor cursor = null;
            try { 
                Log.i(TAG, "Attendees orphans:");
                cursor = db.rawQuery(SELECT_ATTENDEES_ORPHANS, null);
                DatabaseUtils.dumpCursor(cursor);
            } finally { 
                if (cursor != null) {
                    cursor.close();
                } 
            } 
 
            String SELECT_REMINDERS_ORPHANS = "SELECT " +
                    Attendees._ID + ", " + Reminders.EVENT_ID + " FROM " + Tables.REMINDERS +
                    " WHERE " + WHERE_REMINDERS_ORPHANS;
            cursor = null;
            try { 
                Log.i(TAG, "Reminders orphans:");
                cursor = db.rawQuery(SELECT_REMINDERS_ORPHANS, null);
                DatabaseUtils.dumpCursor(cursor);
            } finally { 
                if (cursor != null) {
                    cursor.close();
                } 
            } 
 
            return; 
        } 
 
        Log.d(TAG, "Checking for orphaned entries");
        int count;
 
        count = db.delete(Tables.ATTENDEES, WHERE_ATTENDEES_ORPHANS, null);
        if (count != 0) {
            Log.i(TAG, "Deleted " + count + " orphaned Attendees");
        } 
 
        count = db.delete(Tables.REMINDERS, WHERE_REMINDERS_ORPHANS, null);
        if (count != 0) {
            Log.i(TAG, "Deleted " + count + " orphaned Reminders");
        } 
    } 
 
 
    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG, "Upgrading DB from version " + oldVersion + " to " + newVersion);
        long startWhen = System.nanoTime();
 
        if (oldVersion < 49) {
            dropTables(db);
            bootstrapDB(db);
            return; 
        } 
 
        // From schema versions 59 to version 66, the CalendarMetaData table definition had lost 
        // the primary key leading to having the CalendarMetaData with multiple rows instead of 
        // only one. The Instance table was then corrupted (during Instance expansion we are using 
        // the localTimezone, minInstance and maxInstance from CalendarMetaData table. 
        // This boolean helps us tracking the need to recreate the CalendarMetaData table and 
        // clear the Instance table (and thus force an Instance expansion). 
        boolean recreateMetaDataAndInstances = (oldVersion >= 59 && oldVersion <= 66);
        boolean createEventsView = false;
 
        try { 
            if (oldVersion < 51) {
                upgradeToVersion51(db); // From 50 or 51
                oldVersion = 51;
            } 
            if (oldVersion == 51) {
                upgradeToVersion52(db);
                oldVersion += 1;
            } 
            if (oldVersion == 52) {
                upgradeToVersion53(db);
                oldVersion += 1;
            } 
            if (oldVersion == 53) {
                upgradeToVersion54(db);
                oldVersion += 1;
            } 
            if (oldVersion == 54) {
                upgradeToVersion55(db);
                oldVersion += 1;
            } 
            if (oldVersion == 55 || oldVersion == 56) {
                // Both require resync, so just schedule it once 
                upgradeResync(db);
            } 
            if (oldVersion == 55) {
                upgradeToVersion56(db);
                oldVersion += 1;
            } 
            if (oldVersion == 56) {
                upgradeToVersion57(db);
                oldVersion += 1;
            } 
            if (oldVersion == 57) {
                // Changes are undone upgrading to 60, so don't do anything. 
                oldVersion += 1;
            } 
            if (oldVersion == 58) {
                upgradeToVersion59(db);
                oldVersion += 1;
            } 
            if (oldVersion == 59) {
                upgradeToVersion60(db);
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 60) {
                upgradeToVersion61(db);
                oldVersion += 1;
            } 
            if (oldVersion == 61) {
                upgradeToVersion62(db);
                oldVersion += 1;
            } 
            if (oldVersion == 62) {
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 63) {
                upgradeToVersion64(db);
                oldVersion += 1;
            } 
            if (oldVersion == 64) {
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 65) {
                upgradeToVersion66(db);
                oldVersion += 1;
            } 
            if (oldVersion == 66) {
                // Changes are done thru recreateMetaDataAndInstances() method 
                oldVersion += 1;
            } 
            if (recreateMetaDataAndInstances) {
                recreateMetaDataAndInstances67(db);
            } 
            if (oldVersion == 67 || oldVersion == 68) {
                upgradeToVersion69(db);
                oldVersion = 69;
            } 
            // 69. 70 are for Froyo/old Gingerbread only and 100s are for Gingerbread only 
            // 70 and 71 have been for Honeycomb but no more used 
            // 72 and 73 and 74 were for Honeycomb only but are considered as obsolete for enabling 
            // room for Froyo version numbers 
            if(oldVersion == 69) {
                upgradeToVersion200(db);
                createEventsView = true;
                oldVersion = 200;
            } 
            if (oldVersion == 70) {
                upgradeToVersion200(db);
                oldVersion = 200;
            } 
            if (oldVersion == 100) {
                // note we skip past v101 and v102 
                upgradeToVersion200(db);
                oldVersion = 200;
            } 
            boolean need203Update = true;
            if (oldVersion == 101 || oldVersion == 102) {
                // v101 is v100 plus updateCalendarCacheTableTo203(). 
                // v102 is v101 with Event._id changed to autoincrement. 
                // Upgrade to 200 and skip the 203 update. 
                upgradeToVersion200(db);
                oldVersion = 200;
                need203Update = false;
            } 
            if (oldVersion == 200) {
                upgradeToVersion201(db);
                oldVersion += 1;
            } 
            if (oldVersion == 201) {
                upgradeToVersion202(db);
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 202) {
                if (need203Update) {
                    upgradeToVersion203(db);
                } 
                oldVersion += 1;
            } 
            if (oldVersion == 203) {
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 206) {
                // v206 exists only in HC (change Event._id to autoincrement).  Otherwise 
                // identical to v204, so back it up and let the upgrade path continue. 
                oldVersion -= 2;
            } 
            if (oldVersion == 204) {
                // This is an ICS update, all following use 300+ versions. 
                upgradeToVersion205(db);
                createEventsView = true;
                oldVersion += 1;
            } 
            if (oldVersion == 205) {
                // Move ICS updates to 300 range 
                upgradeToVersion300(db);
                createEventsView = true;
                oldVersion = 300;
            } 
            if (oldVersion == 300) {
                upgradeToVersion301(db);
                createEventsView = true;
                oldVersion++;
            } 
            if (oldVersion == 301) {
                upgradeToVersion302(db);
                oldVersion++;
            } 
            if (oldVersion == 302) {
                upgradeToVersion303(db);
                oldVersion++;
                createEventsView = true;
            } 
            if (oldVersion == 303) {
                upgradeToVersion304(db);
                oldVersion++;
                createEventsView = true;
            } 
            if (oldVersion == 304) {
                upgradeToVersion305(db);
                oldVersion++;
                createEventsView = true;
            } 
            if (oldVersion == 305) {
                upgradeToVersion306(db);
                // force a sync to update edit url and etag 
                scheduleSync(null /* all accounts */, false, null); 
                oldVersion++;
            } 
            if (oldVersion == 306) {
                upgradeToVersion307(db);
                oldVersion++;
            } 
            if (oldVersion == 307) {
                upgradeToVersion308(db);
                oldVersion++;
                createEventsView = true;
            } 
            if (oldVersion == 308) {
                upgradeToVersion400(db);
                createEventsView = true;
                oldVersion = 400;
            } 
            // 309 was changed to 400 since it is the first change of the J release. 
            if (oldVersion == 309 || oldVersion == 400) {
                upgradeToVersion401(db);
                createEventsView = true;
                oldVersion = 401;
            } 
            if (oldVersion == 401) {
                upgradeToVersion402(db);
                createEventsView = true;
                oldVersion = 402;
            } 
            if (oldVersion == 402) {
                upgradeToVersion403(db);
                createEventsView = true;
                oldVersion = 403;
            } 
            if (oldVersion == 403) {
                upgradeToVersion501(db);
                createEventsView = true;
                oldVersion = 501;
            } 
            if (oldVersion == 501) {
                upgradeToVersion502(db);
                createEventsView = true; // This is needed if the calendars or events schema changed
                oldVersion = 502;
            } 
            if (oldVersion < 600) {
                upgradeToVersion600(db);
                createEventsView = true; // This is needed if the calendars or events schema changed
                oldVersion = 600;
            } 
 
            if (createEventsView) {
                createEventsView(db);
            } 
            if (oldVersion != DATABASE_VERSION) {
                Log.e(TAG, "Need to recreate Calendar schema because of "
                        + "unknown Calendar database version: " + oldVersion);
                dropTables(db);
                bootstrapDB(db);
                oldVersion = DATABASE_VERSION;
            } else { 
                removeOrphans(db);
            } 
        } catch (SQLiteException e) {
            if (mInTestMode) {
                // We do want to crash if we are in test mode. 
                throw e;
            } 
            Log.e(TAG, "onUpgrade: SQLiteException, recreating db. ", e);
            Log.e(TAG, "(oldVersion was " + oldVersion + ")");
            dropTables(db);
            bootstrapDB(db);
            return; // this was lossy 
        } 
 
        long endWhen = System.nanoTime();
        Log.d(TAG, "Calendar upgrade took " + ((endWhen - startWhen) / 1000000) + "ms");
 
        /** 
         * db versions < 100 correspond to Froyo and earlier. Gingerbread bumped 
         * the db versioning to 100. Honeycomb bumped it to 200. ICS will begin 
         * in 300. At each major release we should jump to the next 
         * centiversion. 
         */ 
    } 
 
    @Override 
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG, "Can't downgrade DB from version " + oldVersion + " to " + newVersion);
        dropTables(db);
        bootstrapDB(db);
        return; 
    } 
 
    /** 
     * If the user_version of the database if between 59 and 66 (those versions has been deployed 
     * with no primary key for the CalendarMetaData table) 
     */ 
    private void recreateMetaDataAndInstances67(SQLiteDatabase db) {
        // Recreate the CalendarMetaData table with correct primary key 
        db.execSQL("DROP TABLE CalendarMetaData;");
        createCalendarMetaDataTable59(db);
 
        // Also clean the Instance table as this table may be corrupted 
        db.execSQL("DELETE FROM Instances;");
    } 
 
    private static boolean fixAllDayTime(Time time, String timezone, Long timeInMillis) {
        time.set(timeInMillis);
        if(time.hour != 0 || time.minute != 0 || time.second != 0) {
            time.hour = 0;
            time.minute = 0;
            time.second = 0;
            return true; 
        } 
        return false; 
    } 
 
    /**********************************************************/ 
    /* DO NOT USE CONSTANTS FOR UPGRADES, USE STRING LITERALS */ 
    /**********************************************************/ 
 
    /**********************************************************/ 
    /* 6xx db version is for K release 
    /**********************************************************/ 
 
    private void upgradeToVersion600(SQLiteDatabase db) {
        /* 
         * Changes from version 5xx to 600: 
         * - add mutator columns to Events & calendars 
         */ 
        db.execSQL("ALTER TABLE Events ADD COLUMN mutators TEXT;");
        db.execSQL("ALTER TABLE Calendars ADD COLUMN mutators TEXT;");
    } 
 
    /**********************************************************/ 
    /* 5xx db version is for JB MR1 release 
    /**********************************************************/ 
 
    private void upgradeToVersion501(SQLiteDatabase db) {
        /* 
         * Changes from version 403 to 501: 
         * - add isOrganizer column to Events table 
         * - add isPrimary column to Calendars table 
         */ 
        db.execSQL("ALTER TABLE Events ADD COLUMN isOrganizer INTEGER;");
        db.execSQL("ALTER TABLE Calendars ADD COLUMN isPrimary INTEGER;");
    } 
 
    private void upgradeToVersion502(SQLiteDatabase db) {
        /* 
         * Changes from version 501 to 502: 
         * - add UID for events added from the RFC 2445 iCalendar format. 
         */ 
        db.execSQL("ALTER TABLE Events ADD COLUMN uid2445 TEXT;");
    } 
 
    /**********************************************************/ 
    /* 4xx db version is for J release 
    /**********************************************************/ 
 
    private void upgradeToVersion403(SQLiteDatabase db) {
        /* 
         * Changes from version 402 to 403: 
         * - add custom app package name and uri Events table 
         */ 
        db.execSQL("ALTER TABLE Events ADD COLUMN customAppPackage TEXT;");
        db.execSQL("ALTER TABLE Events ADD COLUMN customAppUri TEXT;");
    } 
 
    private void upgradeToVersion402(SQLiteDatabase db) {
        /* 
         * Changes from version 401 to 402: 
         * - add identity and namespace to Attendees table 
         */ 
        db.execSQL("ALTER TABLE Attendees ADD COLUMN attendeeIdentity TEXT;");
        db.execSQL("ALTER TABLE Attendees ADD COLUMN attendeeIdNamespace TEXT;");
    } 
 
    /* 
     * Changes from version 309 to 401: 
     * Fix repeating events' exceptions with the wrong original_id 
     */ 
    private void upgradeToVersion401(SQLiteDatabase db) {
        db.execSQL("UPDATE events SET original_id=(SELECT _id FROM events inner_events WHERE " +
                "inner_events._sync_id=events.original_sync_id AND " + 
                "inner_events.calendar_id=events.calendar_id) WHERE NOT original_id IS NULL AND " + 
                "(SELECT calendar_id FROM events ex_events WHERE " + 
                "ex_events._id=events.original_id) <> calendar_id "); 
    } 
 
    private void upgradeToVersion400(SQLiteDatabase db) {
        db.execSQL("DROP TRIGGER IF EXISTS calendar_color_update");
        // CREATE_CALENDAR_COLOR_UPDATE_TRIGGER was inlined 
        db.execSQL("CREATE TRIGGER "
                + "calendar_color_update" + " UPDATE OF " + Calendars.CALENDAR_COLOR_KEY
                + " ON " + Tables.CALENDARS + " WHEN new." + Calendars.CALENDAR_COLOR_KEY
                + " NOT NULL BEGIN " + "UPDATE " + Tables.CALENDARS
                + " SET calendar_color=(SELECT " + Colors.COLOR + " FROM " + Tables.COLORS
                + " WHERE " + Colors.ACCOUNT_NAME + "=" + "new." + Calendars.ACCOUNT_NAME + " AND "
                + Colors.ACCOUNT_TYPE + "=" + "new." + Calendars.ACCOUNT_TYPE + " AND "
                + Colors.COLOR_KEY + "=" + "new." + Calendars.CALENDAR_COLOR_KEY + " AND "
                + Colors.COLOR_TYPE + "=" + Colors.TYPE_CALENDAR + ") "
                + " WHERE " + Calendars._ID + "=" + "old." + Calendars._ID
                + ";" + " END"); 
        db.execSQL("DROP TRIGGER IF EXISTS event_color_update");
        // CREATE_EVENT_COLOR_UPDATE_TRIGGER was inlined 
        db.execSQL("CREATE TRIGGER "
                + "event_color_update" + " UPDATE OF " + Events.EVENT_COLOR_KEY + " ON "
                + Tables.EVENTS + " WHEN new." + Events.EVENT_COLOR_KEY + " NOT NULL BEGIN "
                + "UPDATE " + Tables.EVENTS
                + " SET eventColor=(SELECT " + Colors.COLOR + " FROM " + Tables.COLORS + " WHERE "
                + Colors.ACCOUNT_NAME + "=" + "(SELECT " + Calendars.ACCOUNT_NAME + " FROM "
                + Tables.CALENDARS + " WHERE " + Calendars._ID + "=new." + Events.CALENDAR_ID
                + ") AND " + Colors.ACCOUNT_TYPE + "=" + "(SELECT " + Calendars.ACCOUNT_TYPE
                + " FROM " + Tables.CALENDARS + " WHERE " + Calendars._ID + "=new."
                + Events.CALENDAR_ID + ") AND " + Colors.COLOR_KEY + "=" + "new."
                + Events.EVENT_COLOR_KEY + " AND " + Colors.COLOR_TYPE + "="
                + Colors.TYPE_EVENT + ") "
                + " WHERE " + Events._ID + "=" + "old." + Events._ID + ";" + " END");
    } 
 
    private void upgradeToVersion308(SQLiteDatabase db) {
        /* 
         * Changes from version 307 to 308: 
         * - add Colors table to db 
         * - add eventColor_index to Events table 
         * - add calendar_color_index to Calendars table 
         * - add allowedAttendeeTypes to Calendars table 
         * - add allowedAvailability to Calendars table 
         */ 
        createColorsTable(db);
 
        db.execSQL("ALTER TABLE Calendars ADD COLUMN allowedAvailability TEXT DEFAULT '0,1';");
        db.execSQL("ALTER TABLE Calendars ADD COLUMN allowedAttendeeTypes TEXT DEFAULT '0,1,2';");
        db.execSQL("ALTER TABLE Calendars ADD COLUMN calendar_color_index TEXT;");
        db.execSQL("ALTER TABLE Events ADD COLUMN eventColor_index TEXT;");
 
        // Default Exchange calendars to be supporting the 'tentative' 
        // availability as well 
        db.execSQL("UPDATE Calendars SET allowedAvailability='0,1,2' WHERE _id IN "
                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');"); 
 
        // Triggers to update the color stored in an event or a calendar when 
        // the color_index is changed. 
        createColorsTriggers(db);
    } 
 
    private void upgradeToVersion307(SQLiteDatabase db) {
        /* 
         * Changes from version 306 to 307: 
         * - Changed _id field to AUTOINCREMENT 
         */ 
        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
        db.execSQL("DROP TRIGGER IF EXISTS original_sync_update");
        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
        createEventsTable307(db);
 
        String FIELD_LIST =
            "_id, " + 
            "_sync_id, " + 
            "dirty, " + 
            "lastSynced," + 
            "calendar_id, " + 
            "title, " + 
            "eventLocation, " + 
            "description, " + 
            "eventColor, " + 
            "eventStatus, " + 
            "selfAttendeeStatus, " + 
            "dtstart, " + 
            "dtend, " + 
            "eventTimezone, " + 
            "duration, " + 
            "allDay, " + 
            "accessLevel, " + 
            "availability, " + 
            "hasAlarm, " + 
            "hasExtendedProperties, " + 
            "rrule, " + 
            "rdate, " + 
            "exrule, " + 
            "exdate, " + 
            "original_id," + 
            "original_sync_id, " + 
            "originalInstanceTime, " + 
            "originalAllDay, " + 
            "lastDate, " + 
            "hasAttendeeData, " + 
            "guestsCanModify, " + 
            "guestsCanInviteOthers, " + 
            "guestsCanSeeGuests, " + 
            "organizer, " + 
            "deleted, " + 
            "eventEndTimezone, " + 
            "sync_data1," + 
            "sync_data2," + 
            "sync_data3," + 
            "sync_data4," + 
            "sync_data5," + 
            "sync_data6," + 
            "sync_data7," + 
            "sync_data8," + 
            "sync_data9," + 
            "sync_data10 "; 
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Events (" + FIELD_LIST + ") SELECT " + FIELD_LIST +
                "FROM Events_Backup;"); 
 
        db.execSQL("DROP TABLE Events_Backup;");
 
        // Trigger to remove data tied to an event when we delete that event. 
        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
                "BEGIN " + EVENTS_CLEANUP_TRIGGER_SQL + "END");
 
        // Trigger to update exceptions when an original event updates its 
        // _sync_id 
        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
    } 
 
    private void upgradeToVersion306(SQLiteDatabase db) {
        /* 
        * The following changes are for google.com accounts only. 
        * 
        * Change event id's from ".../private/full/... to .../events/... 
        * Set Calendars.canPartiallyUpdate to 1 to support partial updates 
        * Nuke sync state so we re-sync with a fresh etag and edit url 
        * 
        * We need to drop the original_sync_update trigger because it fires whenever the 
        * sync_id field is touched, and dramatically slows this operation. 
        */ 
        db.execSQL("DROP TRIGGER IF EXISTS original_sync_update");
        db.execSQL("UPDATE Events SET "
                + "_sync_id = REPLACE(_sync_id, '/private/full/', '/events/'), " 
                + "original_sync_id = REPLACE(original_sync_id, '/private/full/', '/events/') " 
                + "WHERE _id IN (SELECT Events._id FROM Events " 
                +    "JOIN Calendars ON Events.calendar_id = Calendars._id " 
                +    "WHERE account_type = 'com.google')" 
        ); 
        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
 
        db.execSQL("UPDATE Calendars SET canPartiallyUpdate = 1 WHERE account_type = 'com.google'");
 
        db.execSQL("DELETE FROM _sync_state WHERE account_type = 'com.google'");
    } 
 
    private void upgradeToVersion305(SQLiteDatabase db) {
        /* 
         * Changes from version 304 to 305: 
         * -Add CAL_SYNC columns up to 10 
         * -Rename Calendars.access_level to calendar_access_level 
         * -Rename calendars _sync_version to cal_sync7 
         * -Rename calendars _sync_time to cal_sync8 
         * -Rename displayName to calendar_displayName 
         * -Rename _sync_local_id to sync_data2 
         * -Rename htmlUri to sync_data3 
         * -Rename events _sync_version to sync_data4 
         * -Rename events _sync_time to sync_data5 
         * -Rename commentsUri to sync_data6 
         * -Migrate Events _sync_mark to sync_data8 
         * -Change sync_data2 from INTEGER to TEXT 
         * -Change sync_data8 from INTEGER to TEXT 
         * -Add SYNC_DATA columns up to 10 
         * -Add EVENT_COLOR to Events table 
         */ 
 
        // rename old table, create new table with updated layout 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        createCalendarsTable305(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "account_name, " + 
                "account_type, " + 
                "_sync_id, " + 
                "cal_sync7, " +             // rename from _sync_version 
                "cal_sync8, " +             // rename from _sync_time 
                "dirty, " + 
                "name, " + 
                "calendar_displayName, " +  // rename from displayName 
                "calendar_color, " + 
                "calendar_access_level, " + // rename from access_level 
                "visible, " + 
                "sync_events, " + 
                "calendar_location, " + 
                "calendar_timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "allowedReminders, " + 
                "deleted, " + 
                "canPartiallyUpdate," + 
                "cal_sync1, " + 
                "cal_sync2, " + 
                "cal_sync3, " + 
                "cal_sync4, " + 
                "cal_sync5, " + 
                "cal_sync6) " + 
                "SELECT " + 
                "_id, " + 
                "account_name, " + 
                "account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "dirty, " + 
                "name, " + 
                "displayName, " + 
                "calendar_color, " + 
                "access_level, " + 
                "visible, " + 
                "sync_events, " + 
                "calendar_location, " + 
                "calendar_timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "allowedReminders, " + 
                "deleted, " + 
                "canPartiallyUpdate," + 
                "cal_sync1, " + 
                "cal_sync2, " + 
                "cal_sync3, " + 
                "cal_sync4, " + 
                "cal_sync5, " + 
                "cal_sync6 " + 
                "FROM Calendars_Backup;"); 
 
        // drop the old table 
        db.execSQL("DROP TABLE Calendars_Backup;");
 
        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
        // 305 and 307 can share the same createEventsTable implementation, because the 
        // addition of "autoincrement" to _ID doesn't affect the upgrade path.  (Note that 
        // much older databases may also already have autoincrement set because the change 
        // was back-ported.) 
        createEventsTable307(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Events (" +
                "_id, " + 
                "_sync_id, " + 
                "sync_data4, " +        // renamed from _sync_version 
                "sync_data5, " +        // renamed from _sync_time 
                "sync_data2, " +        // renamed from _sync_local_id 
                "dirty, " + 
                "sync_data8, " +        // renamed from _sync_mark 
                "calendar_id, " + 
                "sync_data3, " +        // renamed from htmlUri 
                "title, " + 
                "eventLocation, " + 
                "description, " + 
                "eventStatus, " + 
                "selfAttendeeStatus, " + 
                "sync_data6, " +        // renamed from commentsUri 
                "dtstart, " + 
                "dtend, " + 
                "eventTimezone, " + 
                "eventEndTimezone, " + 
                "duration, " + 
                "allDay, " + 
                "accessLevel, " + 
                "availability, " + 
                "hasAlarm, " + 
                "hasExtendedProperties, " + 
                "rrule, " + 
                "rdate, " + 
                "exrule, " + 
                "exdate, " + 
                "original_id," + 
                "original_sync_id, " + 
                "originalInstanceTime, " + 
                "originalAllDay, " + 
                "lastDate, " + 
                "hasAttendeeData, " + 
                "guestsCanModify, " + 
                "guestsCanInviteOthers, " + 
                "guestsCanSeeGuests, " + 
                "organizer, " + 
                "deleted, " + 
                "sync_data7," + 
                "lastSynced," + 
                "sync_data1) " + 
 
                "SELECT " + 
                "_id, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "dirty, " + 
                "_sync_mark, " + 
                "calendar_id, " + 
                "htmlUri, " + 
                "title, " + 
                "eventLocation, " + 
                "description, " + 
                "eventStatus, " + 
                "selfAttendeeStatus, " + 
                "commentsUri, " + 
                "dtstart, " + 
                "dtend, " + 
                "eventTimezone, " + 
                "eventEndTimezone, " + 
                "duration, " + 
                "allDay, " + 
                "accessLevel, " + 
                "availability, " + 
                "hasAlarm, " + 
                "hasExtendedProperties, " + 
                "rrule, " + 
                "rdate, " + 
                "exrule, " + 
                "exdate, " + 
                "original_id," + 
                "original_sync_id, " + 
                "originalInstanceTime, " + 
                "originalAllDay, " + 
                "lastDate, " + 
                "hasAttendeeData, " + 
                "guestsCanModify, " + 
                "guestsCanInviteOthers, " + 
                "guestsCanSeeGuests, " + 
                "organizer, " + 
                "deleted, " + 
                "sync_data7," + 
                "lastSynced," + 
                "sync_data1 " + 
 
                "FROM Events_Backup;" 
        ); 
 
        db.execSQL("DROP TABLE Events_Backup;");
 
        // Trigger to remove data tied to an event when we delete that event. 
        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
                "BEGIN " + 
                EVENTS_CLEANUP_TRIGGER_SQL +
                "END"); 
 
        // Trigger to update exceptions when an original event updates its 
        // _sync_id 
        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
    } 
 
    private void upgradeToVersion304(SQLiteDatabase db) {
        /* 
         * Changes from version 303 to 304: 
         * - add canPartiallyUpdate to Calendars table 
         * - add sync_data7 to Calendars to Events table 
         * - add lastSynced to Calendars to Events table 
         */ 
        db.execSQL("ALTER TABLE Calendars ADD COLUMN canPartiallyUpdate INTEGER DEFAULT 0;");
        db.execSQL("ALTER TABLE Events ADD COLUMN sync_data7 TEXT;");
        db.execSQL("ALTER TABLE Events ADD COLUMN lastSynced INTEGER DEFAULT 0;");
    } 
 
    private void upgradeToVersion303(SQLiteDatabase db) {
        /* 
         * Changes from version 302 to 303: 
         * - change SYNCx columns to CAL_SYNCx 
         */ 
 
        // rename old table, create new table with updated layout 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        createCalendarsTable303(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "account_name, " + 
                "account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "dirty, " + 
                "name, " + 
                "displayName, " + 
                "calendar_color, " + 
                "access_level, " + 
                "visible, " + 
                "sync_events, " + 
                "calendar_location, " + 
                "calendar_timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "allowedReminders, " + 
                "deleted, " + 
                "cal_sync1, " +     // rename from sync1 
                "cal_sync2, " +     // rename from sync2 
                "cal_sync3, " +     // rename from sync3 
                "cal_sync4, " +     // rename from sync4 
                "cal_sync5, " +     // rename from sync5 
                "cal_sync6) " +     // rename from sync6 
                "SELECT " + 
                "_id, " + 
                "account_name, " + 
                "account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "dirty, " + 
                "name, " + 
                "displayName, " + 
                "calendar_color, " + 
                "access_level, " + 
                "visible, " + 
                "sync_events, " + 
                "calendar_location, " + 
                "calendar_timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "allowedReminders," + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4," + 
                "sync5," + 
                "sync6 " + 
                "FROM Calendars_Backup;" 
        ); 
 
        // drop the old table 
        db.execSQL("DROP TABLE Calendars_Backup;");
    } 
 
    private void upgradeToVersion302(SQLiteDatabase db) {
        /* 
         * Changes from version 301 to 302 
         * - Move Exchange eventEndTimezone values to SYNC_DATA1 
         */ 
        db.execSQL("UPDATE Events SET sync_data1=eventEndTimezone WHERE calendar_id IN "
                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');"); 
 
        db.execSQL("UPDATE Events SET eventEndTimezone=NULL WHERE calendar_id IN "
                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');"); 
    } 
 
    private void upgradeToVersion301(SQLiteDatabase db) {
        /* 
         * Changes from version 300 to 301 
         * - Added original_id column to Events table 
         * - Added triggers to keep original_id and original_sync_id in sync 
         */ 
 
        db.execSQL("DROP TRIGGER IF EXISTS " + SYNC_ID_UPDATE_TRIGGER_NAME + ";");
 
        db.execSQL("ALTER TABLE Events ADD COLUMN original_id INTEGER;");
 
        // Fill in the original_id for all events that have an original_sync_id 
        db.execSQL("UPDATE Events set original_id=" +
                "(SELECT Events2._id FROM Events AS Events2 " + 
                        "WHERE Events2._sync_id=Events.original_sync_id) " + 
                "WHERE Events.original_sync_id NOT NULL"); 
        // Trigger to update exceptions when an original event updates its 
        // _sync_id 
        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
    } 
 
    private void upgradeToVersion300(SQLiteDatabase db) {
 
        /* 
         * Changes from version 205 to 300: 
         * - rename _sync_account to account_name in Calendars table 
         * - remove _sync_account from Events table 
         * - rename _sync_account_type to account_type in Calendars table 
         * - remove _sync_account_type from Events table 
         * - rename _sync_dirty to dirty in Calendars/Events table 
         * - rename color to calendar_color in Calendars table 
         * - rename location to calendar_location in Calendars table 
         * - rename timezone to calendar_timezone in Calendars table 
         * - add allowedReminders in Calendars table 
         * - rename visibility to accessLevel in Events table 
         * - rename transparency to availability in Events table 
         * - rename originalEvent to original_sync_id in Events table 
         * - remove dtstart2 and dtend2 from Events table 
         * - rename syncAdapterData to sync_data1 in Events table 
         */ 
 
        // rename old table, create new table with updated layout 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup;");
        createCalendarsTable300(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "account_name, " +          // rename from _sync_account 
                "account_type, " +          // rename from _sync_account_type 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "dirty, " +                 // rename from _sync_dirty 
                "name, " + 
                "displayName, " + 
                "calendar_color, " +        // rename from color 
                "access_level, " + 
                "visible, " + 
                "sync_events, " + 
                "calendar_location, " +     // rename from location 
                "calendar_timezone, " +     // rename from timezone 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "allowedReminders," + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4," + 
                "sync5," + 
                "sync6) " + 
 
                "SELECT " + 
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_dirty, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "visible, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " + 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "'0,1,2,3'," + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4, " + 
                "sync5, " + 
                "sync6 " + 
                "FROM Calendars_Backup;" 
        ); 
 
        /* expand the set of allowed reminders for Google calendars to include email */ 
        db.execSQL("UPDATE Calendars SET allowedReminders = '0,1,2' " +
                "WHERE account_type = 'com.google'"); 
 
        // drop the old table 
        db.execSQL("DROP TABLE Calendars_Backup;");
 
        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS events_insert");
        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
        db.execSQL("DROP INDEX IF EXISTS eventSyncAccountAndIdIndex");
        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
        createEventsTable300(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Events (" +
                "_id, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "dirty, " +                 // renamed from _sync_dirty 
                "_sync_mark, " + 
                "calendar_id, " + 
                "htmlUri, " + 
                "title, " + 
                "eventLocation, " + 
                "description, " + 
                "eventStatus, " + 
                "selfAttendeeStatus, " + 
                "commentsUri, " + 
                "dtstart, " + 
                "dtend, " + 
                "eventTimezone, " + 
                "eventEndTimezone, " +      // renamed from eventTimezone2 
                "duration, " + 
                "allDay, " + 
                "accessLevel, " +           // renamed from visibility 
                "availability, " +          // renamed from transparency 
                "hasAlarm, " + 
                "hasExtendedProperties, " + 
                "rrule, " + 
                "rdate, " + 
                "exrule, " + 
                "exdate, " + 
                "original_sync_id, " +      // renamed from originalEvent 
                "originalInstanceTime, " + 
                "originalAllDay, " + 
                "lastDate, " + 
                "hasAttendeeData, " + 
                "guestsCanModify, " + 
                "guestsCanInviteOthers, " + 
                "guestsCanSeeGuests, " + 
                "organizer, " + 
                "deleted, " + 
                "sync_data1) " +             // renamed from syncAdapterData 
 
                "SELECT " + 
                "_id, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "_sync_dirty, " + 
                "_sync_mark, " + 
                "calendar_id, " + 
                "htmlUri, " + 
                "title, " + 
                "eventLocation, " + 
                "description, " + 
                "eventStatus, " + 
                "selfAttendeeStatus, " + 
                "commentsUri, " + 
                "dtstart, " + 
                "dtend, " + 
                "eventTimezone, " + 
                "eventTimezone2, " + 
                "duration, " + 
                "allDay, " + 
                "visibility, " + 
                "transparency, " + 
                "hasAlarm, " + 
                "hasExtendedProperties, " + 
                "rrule, " + 
                "rdate, " + 
                "exrule, " + 
                "exdate, " + 
                "originalEvent, " + 
                "originalInstanceTime, " + 
                "originalAllDay, " + 
                "lastDate, " + 
                "hasAttendeeData, " + 
                "guestsCanModify, " + 
                "guestsCanInviteOthers, " + 
                "guestsCanSeeGuests, " + 
                "organizer, " + 
                "deleted, " + 
                "syncAdapterData " + 
 
                "FROM Events_Backup;" 
        ); 
 
        db.execSQL("DROP TABLE Events_Backup;");
 
        // Trigger to remove data tied to an event when we delete that event. 
        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
                "BEGIN " + 
                EVENTS_CLEANUP_TRIGGER_SQL +
                "END"); 
 
    } 
 
    private void upgradeToVersion205(SQLiteDatabase db) {
        /* 
         * Changes from version 204 to 205: 
         * - rename+reorder "_sync_mark" to "sync6" (and change type from INTEGER to TEXT) 
         * - rename "selected" to "visible" 
         * - rename "organizerCanRespond" to "canOrganizerRespond" 
         * - add "canModifyTimeZone" 
         * - add "maxReminders" 
         * - remove "_sync_local_id" (a/k/a _SYNC_DATA) 
         */ 
 
        // rename old table, create new table with updated layout 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        createCalendarsTable205(db);
 
        // copy fields from old to new 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_dirty, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "visible, " +                   // rename from "selected" 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "canOrganizerRespond, " +       // rename from "organizerCanRespond" 
                "canModifyTimeZone, " + 
                "maxReminders, " + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4," + 
                "sync5," + 
                "sync6) " +                     // rename/reorder from _sync_mark 
                "SELECT " + 
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_dirty, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "selected, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "organizerCanRespond, " + 
                "1, " + 
                "5, " + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4, " + 
                "sync5, " + 
                "_sync_mark " + 
                "FROM Calendars_Backup;" 
        ); 
 
        // set these fields appropriately for Exchange events 
        db.execSQL("UPDATE Calendars SET canModifyTimeZone=0, maxReminders=1 " +
                "WHERE _sync_account_type='com.android.exchange'"); 
 
        // drop the old table 
        db.execSQL("DROP TABLE Calendars_Backup;");
    } 
 
    private void upgradeToVersion203(SQLiteDatabase db) {
        // Same as Gingerbread version 100 
        Cursor cursor = db.rawQuery("SELECT value FROM CalendarCache WHERE key=?",
                new String[] {"timezoneDatabaseVersion"});
 
        String oldTimezoneDbVersion = null;
        if (cursor != null) {
            try { 
                if (cursor.moveToNext()) {
                    oldTimezoneDbVersion = cursor.getString(0);
                    cursor.close();
                    cursor = null;
                    // Also clean the CalendarCache table 
                    db.execSQL("DELETE FROM CalendarCache;");
                } 
            } finally { 
                if (cursor != null) {
                    cursor.close();
                } 
            } 
        } 
        initCalendarCacheTable203(db, oldTimezoneDbVersion);
 
        // Same as Gingerbread version 101 
        updateCalendarCacheTableTo203(db);
    } 
 
    private void upgradeToVersion202(SQLiteDatabase db) {
        // We will drop the "hidden" column from the calendar schema and add the "sync5" column 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
 
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        createCalendarsTable202(db);
 
        // Populate the new Calendars table and put into the "sync5" column the value of the 
        // old "hidden" column 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "_sync_dirty, " + 
                "_sync_mark, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "selected, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "organizerCanRespond, " + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4," + 
                "sync5) " + 
                "SELECT " + 
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "_sync_dirty, " + 
                "_sync_mark, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "selected, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "organizerCanRespond, " + 
                "deleted, " + 
                "sync1, " + 
                "sync2, " + 
                "sync3, " + 
                "sync4, " + 
                "hidden " + 
                "FROM Calendars_Backup;" 
        ); 
 
        // Drop the backup table 
        db.execSQL("DROP TABLE Calendars_Backup;");
    } 
 
    private void upgradeToVersion201(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE Calendars ADD COLUMN sync4 TEXT;");
    } 
 
    private void upgradeToVersion200(SQLiteDatabase db) {
        // we cannot use here a Calendar.Calendars,URL constant for "url" as we are trying to make 
        // it disappear so we are keeping the hardcoded name "url" in all the SQLs 
        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
 
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        createCalendarsTable200(db);
 
        // Populate the new Calendars table except the SYNC2 / SYNC3 columns 
        db.execSQL("INSERT INTO Calendars (" +
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "_sync_dirty, " + 
                "_sync_mark, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "selected, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "organizerCanRespond, " + 
                "deleted, " + 
                "sync1) " + 
                "SELECT " + 
                "_id, " + 
                "_sync_account, " + 
                "_sync_account_type, " + 
                "_sync_id, " + 
                "_sync_version, " + 
                "_sync_time, " + 
                "_sync_local_id, " + 
                "_sync_dirty, " + 
                "_sync_mark, " + 
                "name, " + 
                "displayName, " + 
                "color, " + 
                "access_level, " + 
                "selected, " + 
                "sync_events, " + 
                "location, " + 
                "timezone, " + 
                "ownerAccount, " + 
                "organizerCanRespond, " + 
                "0, " + 
                "url " + 
                "FROM Calendars_Backup;" 
        ); 
 
        // Populate SYNC2 and SYNC3 columns - SYNC1 represent the old "url" column 
        // We will need to iterate over all the "com.google" type of calendars 
        String selectSql = "SELECT _id, url" +
                " FROM Calendars_Backup" + 
                " WHERE _sync_account_type='com.google'" + 
                " AND url IS NOT NULL;"; 
 
        String updateSql = "UPDATE Calendars SET " +
                "sync2=?, " + // edit Url 
                "sync3=? " + // self Url 
                "WHERE _id=?;"; 
 
        Cursor cursor = db.rawQuery(selectSql, null /* selection args */);
        if (cursor != null) {
            try { 
                if (cursor.getCount() > 0) {
                    Object[] bindArgs = new Object[3];
                    while (cursor.moveToNext()) {
                        Long id = cursor.getLong(0);
                        String url = cursor.getString(1);
                        String selfUrl = getSelfUrlFromEventsUrl(url);
                        String editUrl = getEditUrlFromEventsUrl(url);
 
                        bindArgs[0] = editUrl;
                        bindArgs[1] = selfUrl;
                        bindArgs[2] = id;
 
                        db.execSQL(updateSql, bindArgs);
                    } 
                } 
            } finally { 
                cursor.close();
            } 
        } 
 
        // Drop the backup table 
        db.execSQL("DROP TABLE Calendars_Backup;");
    } 
 
    @VisibleForTesting 
    public static void upgradeToVersion69(SQLiteDatabase db) {
        // Clean up allDay events which could be in an invalid state from an earlier version 
        // Some allDay events had hour, min, sec not set to zero, which throws elsewhere. This 
        // will go through the allDay events and make sure they have proper values and are in the 
        // correct timezone. Verifies that dtstart and dtend are in UTC and at midnight, that 
        // eventTimezone is set to UTC, tries to make sure duration is in days, and that dtstart2 
        // and dtend2 are at midnight in their timezone. 
        final String sql = "SELECT _id, " +
                "dtstart, " + 
                "dtend, " + 
                "duration, " + 
                "dtstart2, " + 
                "dtend2, " + 
                "eventTimezone, " + 
                "eventTimezone2, " + 
                "rrule " + 
                "FROM Events " + 
                "WHERE allDay=?"; 
        Cursor cursor = db.rawQuery(sql, new String[] {"1"});
        if (cursor != null) {
            try { 
                String timezone;
                String timezone2;
                String duration;
                Long dtstart;
                Long dtstart2;
                Long dtend;
                Long dtend2;
                Time time = new Time();
                Long id;
                // some things need to be in utc so we call this frequently, cache to make faster 
                final String utc = Time.TIMEZONE_UTC;
                while (cursor.moveToNext()) {
                    String rrule = cursor.getString(8);
                    id = cursor.getLong(0);
                    dtstart = cursor.getLong(1);
                    dtstart2 = null;
                    timezone = cursor.getString(6);
                    timezone2 = cursor.getString(7);
                    duration = cursor.getString(3);
 
                    if (TextUtils.isEmpty(rrule)) {
                        // For non-recurring events dtstart and dtend should both have values 
                        // and duration should be null. 
                        dtend = cursor.getLong(2);
                        dtend2 = null;
                        // Since we made all three of these at the same time if timezone2 exists 
                        // so should dtstart2 and dtend2. 
                        if(!TextUtils.isEmpty(timezone2)) {
                            dtstart2 = cursor.getLong(4);
                            dtend2 = cursor.getLong(5);
                        } 
 
                        boolean update = false;
                        if (!TextUtils.equals(timezone, utc)) {
                            update = true;
                            timezone = utc;
                        } 
 
                        time.clear(timezone);
                        update |= fixAllDayTime(time, timezone, dtstart);
                        dtstart = time.normalize(false);
 
                        time.clear(timezone);
                        update |= fixAllDayTime(time, timezone, dtend);
                        dtend = time.normalize(false);
 
                        if (dtstart2 != null) {
                            time.clear(timezone2);
                            update |= fixAllDayTime(time, timezone2, dtstart2);
                            dtstart2 = time.normalize(false);
                        } 
 
                        if (dtend2 != null) {
                            time.clear(timezone2);
                            update |= fixAllDayTime(time, timezone2, dtend2);
                            dtend2 = time.normalize(false);
                        } 
 
                        if (!TextUtils.isEmpty(duration)) {
                            update = true;
                        } 
 
                        if (update) {
                            // enforce duration being null 
                            db.execSQL("UPDATE Events SET " +
                                    "dtstart=?, " + 
                                    "dtend=?, " + 
                                    "dtstart2=?, " + 
                                    "dtend2=?, " + 
                                    "duration=?, " + 
                                    "eventTimezone=?, " + 
                                    "eventTimezone2=? " + 
                                    "WHERE _id=?", 
                                    new Object[] {
                                            dtstart,
                                            dtend,
                                            dtstart2,
                                            dtend2,
                                            null, 
                                            timezone,
                                            timezone2,
                                            id}
                            ); 
                        } 
 
                    } else { 
                        // For recurring events only dtstart and duration should be used. 
                        // We ignore dtend since it will be overwritten if the event changes to a 
                        // non-recurring event and won't be used otherwise. 
                        if(!TextUtils.isEmpty(timezone2)) {
                            dtstart2 = cursor.getLong(4);
                        } 
 
                        boolean update = false;
                        if (!TextUtils.equals(timezone, utc)) {
                            update = true;
                            timezone = utc;
                        } 
 
                        time.clear(timezone);
                        update |= fixAllDayTime(time, timezone, dtstart);
                        dtstart = time.normalize(false);
 
                        if (dtstart2 != null) {
                            time.clear(timezone2);
                            update |= fixAllDayTime(time, timezone2, dtstart2);
                            dtstart2 = time.normalize(false);
                        } 
 
                        if (TextUtils.isEmpty(duration)) {
                            // If duration was missing assume a 1 day duration 
                            duration = "P1D";
                            update = true;
                        } else { 
                            int len = duration.length();
                            // TODO fix durations in other formats as well 
                            if (duration.charAt(0) == 'P' &&
                                    duration.charAt(len - 1) == 'S') {
                                int seconds = Integer.parseInt(duration.substring(1, len - 1));
                                int days = (seconds + DAY_IN_SECONDS - 1) / DAY_IN_SECONDS;
                                duration = "P" + days + "D";
                                update = true;
                            } 
                        } 
 
                        if (update) {
                            // If there were other problems also enforce dtend being null 
                            db.execSQL("UPDATE Events SET " +
                                    "dtstart=?, " + 
                                    "dtend=?, " + 
                                    "dtstart2=?, " + 
                                    "dtend2=?, " + 
                                    "duration=?," + 
                                    "eventTimezone=?, " + 
                                    "eventTimezone2=? " + 
                                    "WHERE _id=?", 
                                    new Object[] {
                                            dtstart,
                                            null, 
                                            dtstart2,
                                            null, 
                                            duration,
                                            timezone,
                                            timezone2,
                                            id}
                            ); 
                        } 
                    } 
                } 
            } finally { 
                cursor.close();
            } 
        } 
    } 
 
    private void upgradeToVersion66(SQLiteDatabase db) {
        // Add a column to indicate whether the event organizer can respond to his own events 
        // The UI should not show attendee status for events in calendars with this column = 0 
        db.execSQL("ALTER TABLE Calendars" +
                " ADD COLUMN organizerCanRespond INTEGER NOT NULL DEFAULT 1;"); 
    } 
 
    private void upgradeToVersion64(SQLiteDatabase db) {
        // Add a column that may be used by sync adapters 
        db.execSQL("ALTER TABLE Events" +
                " ADD COLUMN syncAdapterData TEXT;"); 
    } 
 
    private void upgradeToVersion62(SQLiteDatabase db) {
        // New columns are to transition to having allDay events in the local timezone 
        db.execSQL("ALTER TABLE Events" +
                " ADD COLUMN dtstart2 INTEGER;"); 
        db.execSQL("ALTER TABLE Events" +
                " ADD COLUMN dtend2 INTEGER;"); 
        db.execSQL("ALTER TABLE Events" +
                " ADD COLUMN eventTimezone2 TEXT;"); 
 
        String[] allDayBit = new String[] {"0"};
        // Copy over all the data that isn't an all day event. 
        db.execSQL("UPDATE Events SET " +
                "dtstart2=dtstart," + 
                "dtend2=dtend," + 
                "eventTimezone2=eventTimezone " + 
                "WHERE allDay=?;", 
                allDayBit /* selection args */);
 
        // "cursor" iterates over all the calendars 
        allDayBit[0] = "1";
        Cursor cursor = db.rawQuery("SELECT Events._id," +
                "dtstart," + 
                "dtend," + 
                "eventTimezone," + 
                "timezone " + 
                "FROM Events INNER JOIN Calendars " + 
                "WHERE Events.calendar_id=Calendars._id" + 
                " AND allDay=?", 
                allDayBit /* selection args */);
 
        Time oldTime = new Time();
        Time newTime = new Time();
        // Update the allday events in the new columns 
        if (cursor != null) {
            try { 
                String[] newData = new String[4];
                cursor.moveToPosition(-1);
                while (cursor.moveToNext()) {
                    long id = cursor.getLong(0); // Order from query above
                    long dtstart = cursor.getLong(1);
                    long dtend = cursor.getLong(2);
                    String eTz = cursor.getString(3); // current event timezone
                    String tz = cursor.getString(4); // Calendar timezone
                    //If there's no timezone for some reason use UTC by default. 
                    if(eTz == null) {
                        eTz = Time.TIMEZONE_UTC;
                    } 
 
                    // Convert start time for all day events into the timezone of their calendar 
                    oldTime.clear(eTz);
                    oldTime.set(dtstart);
                    newTime.clear(tz);
                    newTime.set(oldTime.monthDay, oldTime.month, oldTime.year);
                    newTime.normalize(false);
                    dtstart = newTime.toMillis(false /*ignoreDst*/);
 
                    // Convert end time for all day events into the timezone of their calendar 
                    oldTime.clear(eTz);
                    oldTime.set(dtend);
                    newTime.clear(tz);
                    newTime.set(oldTime.monthDay, oldTime.month, oldTime.year);
                    newTime.normalize(false);
                    dtend = newTime.toMillis(false /*ignoreDst*/);
 
                    newData[0] = String.valueOf(dtstart);
                    newData[1] = String.valueOf(dtend);
                    newData[2] = tz;
                    newData[3] = String.valueOf(id);
                    db.execSQL("UPDATE Events SET " +
                            "dtstart2=?, " + 
                            "dtend2=?, " + 
                            "eventTimezone2=? " + 
                            "WHERE _id=?", 
                            newData);
                } 
            } finally { 
                cursor.close();
            } 
        } 
    } 
 
    private void upgradeToVersion61(SQLiteDatabase db) {
        db.execSQL("DROP TABLE IF EXISTS CalendarCache;");
 
        // IF NOT EXISTS should be normal pattern for table creation 
        db.execSQL("CREATE TABLE IF NOT EXISTS CalendarCache (" +
                "_id INTEGER PRIMARY KEY," + 
                "key TEXT NOT NULL," + 
                "value TEXT" + 
                ");"); 
 
        db.execSQL("INSERT INTO CalendarCache (" +
                "key, " + 
                "value) VALUES (" + 
                "'timezoneDatabaseVersion',"  + 
                "'2009s'" + 
                ");"); 
    } 
 
    private void upgradeToVersion60(SQLiteDatabase db) {
        // Switch to CalendarProvider2 
        upgradeSyncState(db);
        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
                "BEGIN " + 
                ("DELETE FROM Events" + 
                        " WHERE calendar_id=old._id;") + 
                "END"); 
        db.execSQL("ALTER TABLE Events" +
                " ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0;"); 
        db.execSQL("DROP TRIGGER IF EXISTS events_insert");
        // Trigger to set event's sync_account 
        db.execSQL("CREATE TRIGGER events_insert AFTER INSERT ON Events " +
                "BEGIN " + 
                "UPDATE Events" + 
                " SET _sync_account=" + 
                " (SELECT _sync_account FROM Calendars" + 
                " WHERE Calendars._id=new.calendar_id)," + 
                "_sync_account_type=" + 
                " (SELECT _sync_account_type FROM Calendars" + 
                " WHERE Calendars._id=new.calendar_id) " + 
                "WHERE Events._id=new._id;" + 
                "END"); 
        db.execSQL("DROP TABLE IF EXISTS DeletedEvents;");
        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
        // Trigger to remove data tied to an event when we delete that event. 
        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON Events " +
                "BEGIN " + 
                ("DELETE FROM Instances" + 
                    " WHERE event_id=old._id;" + 
                "DELETE FROM EventsRawTimes" + 
                    " WHERE event_id=old._id;" + 
                "DELETE FROM Attendees" + 
                    " WHERE event_id=old._id;" + 
                "DELETE FROM Reminders" + 
                    " WHERE event_id=old._id;" + 
                "DELETE FROM CalendarAlerts" + 
                    " WHERE event_id=old._id;" + 
                "DELETE FROM ExtendedProperties" + 
                    " WHERE event_id=old._id;") + 
                "END"); 
        db.execSQL("DROP TRIGGER IF EXISTS attendees_update");
        db.execSQL("DROP TRIGGER IF EXISTS attendees_insert");
        db.execSQL("DROP TRIGGER IF EXISTS attendees_delete");
        db.execSQL("DROP TRIGGER IF EXISTS reminders_update");
        db.execSQL("DROP TRIGGER IF EXISTS reminders_insert");
        db.execSQL("DROP TRIGGER IF EXISTS reminders_delete");
        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_update");
        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_insert");
        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_delete");
    } 
 
    private void upgradeToVersion59(SQLiteDatabase db) {
        db.execSQL("DROP TABLE IF EXISTS BusyBits;");
        db.execSQL("CREATE TEMPORARY TABLE CalendarMetaData_Backup(" +
-7
CodeRank
static DatabaseUtils.longForQuery(SQLiteDatabase,"SELECT version FROM _sync_state_metadata",null)SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS reminders_delete")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS extended_properties_update")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS extended_properties_insert")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS extended_properties_delete")SQLiteDatabase.execSQL("DROP TABLE IF EXISTS DeletedEvents;")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS attendees_delete")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS reminders_update")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS reminders_insert")SQLiteDatabase.execSQL("CREATE TRIGGER events_insert AFTER INSERT ON Events BEGIN UPDATE Events SET _sync_account= (SELECT _sync_account FROM Calendars WHERE Calendars._id=new.calendar_id),_sync_account_type= (SELECT _sync_account_type FROM Calendars WHERE Calendars._id=new.calendar_id) WHERE Events._id=new._id;END")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS events_insert")StartSQLiteDatabase.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars BEGIN DELETE FROM Events WHERE calendar_id=old._id;END")SQLiteDatabase.execSQL("ALTER TABLE Events ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0;")SQLiteDatabase.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON Events BEGIN DELETE FROM Instances WHERE event_id=old._id;DELETE FROM EventsRawTimes WHERE event_id=old._id;DELETE FROM Attendees WHERE event_id=old._id;DELETE FROM Reminders WHERE event_id=old._id;DELETE FROM CalendarAlerts WHERE event_id=old._id;DELETE FROM ExtendedProperties WHERE event_id=old._id;END")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS attendees_insert")SQLiteDatabase.execSQL("DROP TRIGGER IF EXISTS attendees_update")