MmsSmsDatabaseHelper.java revision 62f78e4e0ae991f0df285488a1af382bd5105483
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.telephony;
18
19import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_DELIVERY_IND;
20import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
21import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_ORIG_IND;
22import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_REC_IND;
23import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF;
24import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_SEND_REQ;
25
26import android.content.Context;
27import android.database.Cursor;
28import android.database.sqlite.SQLiteDatabase;
29import android.database.sqlite.SQLiteOpenHelper;
30import android.provider.BaseColumns;
31import android.provider.Telephony.Mms;
32import android.provider.Telephony.MmsSms;
33import android.provider.Telephony.Sms;
34import android.provider.Telephony.Threads;
35import android.provider.Telephony.Mms.Addr;
36import android.provider.Telephony.Mms.Part;
37import android.provider.Telephony.Mms.Rate;
38import android.provider.Telephony.MmsSms.PendingMessages;
39import android.util.Log;
40
41public class MmsSmsDatabaseHelper extends SQLiteOpenHelper {
42    private static final String TAG = "MmsSmsDatabaseHelper";
43
44    private static final String SMS_UPDATE_THREAD_READ_BODY =
45                        "  UPDATE threads SET read = " +
46                        "    CASE (SELECT COUNT(*)" +
47                        "          FROM sms" +
48                        "          WHERE " + Sms.READ + " = 0" +
49                        "            AND " + Sms.THREAD_ID + " = threads._id)" +
50                        "      WHEN 0 THEN 1" +
51                        "      ELSE 0" +
52                        "    END" +
53                        "  WHERE threads._id = new." + Sms.THREAD_ID + "; ";
54
55    private static final String UPDATE_THREAD_COUNT_ON_NEW =
56                        "  UPDATE threads SET message_count = " +
57                        "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
58                        "      ON threads._id = " + Sms.THREAD_ID +
59                        "      WHERE " + Sms.THREAD_ID + " = new.thread_id" +
60                        "        AND sms." + Sms.TYPE + " != 3) + " +
61                        "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
62                        "      ON threads._id = " + Mms.THREAD_ID +
63                        "      WHERE " + Mms.THREAD_ID + " = new.thread_id" +
64                        "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
65                        "        AND " + Mms.MESSAGE_BOX + " != 3) " +
66                        "  WHERE threads._id = new.thread_id; ";
67
68    private static final String UPDATE_THREAD_COUNT_ON_OLD =
69                        "  UPDATE threads SET message_count = " +
70                        "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
71                        "      ON threads._id = " + Sms.THREAD_ID +
72                        "      WHERE " + Sms.THREAD_ID + " = old.thread_id" +
73                        "        AND sms." + Sms.TYPE + " != 3) + " +
74                        "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
75                        "      ON threads._id = " + Mms.THREAD_ID +
76                        "      WHERE " + Mms.THREAD_ID + " = old.thread_id" +
77                        "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
78                        "        AND " + Mms.MESSAGE_BOX + " != 3) " +
79                        "  WHERE threads._id = old.thread_id; ";
80
81    private static final String SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE =
82                        "BEGIN" +
83                        "  UPDATE threads SET" +
84                        "    date = (strftime('%s','now') * 1000), " +
85                        "    snippet = new." + Sms.BODY + ", " +
86                        "    snippet_cs = 0" +
87                        "  WHERE threads._id = new." + Sms.THREAD_ID + "; " +
88                        UPDATE_THREAD_COUNT_ON_NEW +
89                        SMS_UPDATE_THREAD_READ_BODY +
90                        "END;";
91
92    private static final String PDU_UPDATE_THREAD_CONSTRAINTS =
93                        "  WHEN new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF +
94                        "    OR new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND +
95                        "    OR new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_SEND_REQ + " ";
96
97    private static final String PDU_UPDATE_THREAD_READ_BODY =
98                        "  UPDATE threads SET read = " +
99                        "    CASE (SELECT COUNT(*)" +
100                        "          FROM " + MmsProvider.TABLE_PDU +
101                        "          WHERE " + Mms.READ + " = 0" +
102                        "            AND " + Mms.THREAD_ID + " = threads._id)" +
103                        "      WHEN 0 THEN 1" +
104                        "      ELSE 0" +
105                        "    END" +
106                        "  WHERE threads._id = new." + Mms.THREAD_ID + "; ";
107
108    private static final String PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE =
109                        "BEGIN" +
110                        "  UPDATE threads SET" +
111                        "    date = (strftime('%s','now') * 1000), " +
112                        "    snippet = new." + Mms.SUBJECT + ", " +
113                        "    snippet_cs = new." + Mms.SUBJECT_CHARSET +
114                        "  WHERE threads._id = new." + Mms.THREAD_ID + "; " +
115                        UPDATE_THREAD_COUNT_ON_NEW +
116                        PDU_UPDATE_THREAD_READ_BODY +
117                        "END;";
118
119    private static final String UPDATE_THREAD_SNIPPET_SNIPPET_CS_ON_DELETE =
120                        "  UPDATE threads SET snippet = " +
121                        "   (SELECT snippet FROM" +
122                        "     (SELECT date * 1000 AS date, sub AS snippet, thread_id FROM pdu" +
123                        "      UNION SELECT date, body AS snippet, thread_id FROM sms)" +
124                        "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
125                        "  WHERE threads._id = OLD.thread_id; " +
126                        "  UPDATE threads SET snippet_cs = " +
127                        "   (SELECT snippet_cs FROM" +
128                        "     (SELECT date * 1000 AS date, sub_cs AS snippet_cs, thread_id FROM pdu" +
129                        "      UNION SELECT date, 0 AS snippet_cs, thread_id FROM sms)" +
130                        "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
131                        "  WHERE threads._id = OLD.thread_id; ";
132
133    private static MmsSmsDatabaseHelper mInstance = null;
134
135    static final String DATABASE_NAME = "mmssms.db";
136    static final int DATABASE_VERSION = 41;
137
138    private MmsSmsDatabaseHelper(Context context) {
139        super(context, DATABASE_NAME, null, DATABASE_VERSION);
140    }
141
142    /**
143     * Return a singleton helper for the combined MMS and SMS
144     * database.
145     */
146    /* package */ static synchronized MmsSmsDatabaseHelper getInstance(Context context) {
147        if (mInstance == null) {
148            mInstance = new MmsSmsDatabaseHelper(context);
149        }
150        return mInstance;
151    }
152
153    public static void updateThread(SQLiteDatabase db, long thread_id) {
154        if (thread_id < 0) {
155            updateAllThreads(db);
156            return;
157        }
158
159        // Delete the row for this thread in the threads table if
160        // there are no more messages attached to it in either
161        // the sms or pdu tables.
162        int rows = db.delete("threads",
163                  "_id = ? AND _id NOT IN" +
164                  "          (SELECT thread_id FROM sms " +
165                  "           UNION SELECT thread_id FROM pdu)",
166                  new String[] { String.valueOf(thread_id) });
167        if (rows > 0) {
168            // If this deleted a row, we have no more work to do.
169            return;
170        }
171        // Update the message count in the threads table as the sum
172        // of all messages in both the sms and pdu tables.
173        db.execSQL(
174            "  UPDATE threads SET message_count = " +
175            "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
176            "      ON threads._id = " + Sms.THREAD_ID +
177            "      WHERE " + Sms.THREAD_ID + " = " + thread_id +
178            "        AND sms." + Sms.TYPE + " != 3) + " +
179            "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
180            "      ON threads._id = " + Mms.THREAD_ID +
181            "      WHERE " + Mms.THREAD_ID + " = " + thread_id +
182            "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
183            "        AND " + Mms.MESSAGE_BOX + " != 3) " +
184            "  WHERE threads._id = " + thread_id + ";");
185
186        // Update the date and the snippet (and its character set) in
187        // the threads table to be that of the most recent message in
188        // the thread.
189        db.execSQL(
190            "  UPDATE threads" +
191            "  SET" +
192            "  date =" +
193            "    (SELECT date FROM" +
194            "        (SELECT date * 1000 AS date, thread_id FROM pdu" +
195            "         UNION SELECT date, thread_id FROM sms)" +
196            "     WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)," +
197            "  snippet =" +
198            "    (SELECT snippet FROM" +
199            "        (SELECT date * 1000 AS date, sub AS snippet, thread_id FROM pdu" +
200            "         UNION SELECT date, body AS snippet, thread_id FROM sms)" +
201            "     WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)," +
202            "  snippet_cs =" +
203            "    (SELECT snippet_cs FROM" +
204            "        (SELECT date * 1000 AS date, sub_cs AS snippet_cs, thread_id FROM pdu" +
205            "         UNION SELECT date, 0 AS snippet_cs, thread_id FROM sms)" +
206            "     WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)" +
207            "  WHERE threads._id = " + thread_id + ";");
208
209        // Update the error column of the thread to indicate if there
210        // are any messages in it that have failed to send.
211        db.execSQL(
212            "UPDATE threads SET error =" +
213            "       (SELECT COUNT(*) FROM sms WHERE type=5" +
214            "        AND thread_id = " + thread_id + " LIMIT 1)" +
215            "   WHERE threads._id = " + thread_id + ";");
216    }
217
218    public static void updateAllThreads(SQLiteDatabase db) {
219        Cursor c = db.query("threads", new String[] { "_id" },
220                            null, null, null, null, null);
221        if (c != null) {
222            while (c.moveToNext()) {
223                updateThread(db, c.getInt(0));
224            }
225            c.close();
226        }
227    }
228
229    public static int deleteOneSms(SQLiteDatabase db, int message_id) {
230        int thread_id = -1;
231        // Find the thread ID that the specified SMS belongs to.
232        Cursor c = db.query("sms", new String[] { "thread_id" },
233                            "_id=" + message_id, null, null, null, null);
234        if (c != null) {
235            if (c.moveToFirst()) {
236                thread_id = c.getInt(0);
237            }
238            c.close();
239        }
240
241        // Delete the specified message.
242        int rows = db.delete("sms", "_id=" + message_id, null);
243        if (thread_id > 0) {
244            // Update its thread.
245            updateThread(db, thread_id);
246        }
247        return rows;
248    }
249
250    @Override
251    public void onCreate(SQLiteDatabase db) {
252        createMmsTables(db);
253        createSmsTables(db);
254        createCommonTables(db);
255        createCommonTriggers(db);
256        createMmsTriggers(db);
257    }
258
259    private void createMmsTables(SQLiteDatabase db) {
260        // N.B.: Whenever the columns here are changed, the columns in
261        // {@ref MmsSmsProvider} must be changed to match.
262        db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PDU + " (" +
263                   Mms._ID + " INTEGER PRIMARY KEY," +
264                   Mms.THREAD_ID + " INTEGER," +
265                   Mms.DATE + " INTEGER," +
266                   Mms.MESSAGE_BOX + " INTEGER," +
267                   Mms.READ + " INTEGER DEFAULT 0," +
268                   Mms.MESSAGE_ID + " TEXT," +
269                   Mms.SUBJECT + " TEXT," +
270                   Mms.SUBJECT_CHARSET + " INTEGER," +
271                   Mms.CONTENT_TYPE + " TEXT," +
272                   Mms.CONTENT_LOCATION + " TEXT," +
273                   Mms.EXPIRY + " INTEGER," +
274                   Mms.MESSAGE_CLASS + " TEXT," +
275                   Mms.MESSAGE_TYPE + " INTEGER," +
276                   Mms.MMS_VERSION + " INTEGER," +
277                   Mms.MESSAGE_SIZE + " INTEGER," +
278                   Mms.PRIORITY + " INTEGER," +
279                   Mms.READ_REPORT + " INTEGER," +
280                   Mms.REPORT_ALLOWED + " INTEGER," +
281                   Mms.RESPONSE_STATUS + " INTEGER," +
282                   Mms.STATUS + " INTEGER," +
283                   Mms.TRANSACTION_ID + " TEXT," +
284                   Mms.RETRIEVE_STATUS + " INTEGER," +
285                   Mms.RETRIEVE_TEXT + " TEXT," +
286                   Mms.RETRIEVE_TEXT_CHARSET + " INTEGER," +
287                   Mms.READ_STATUS + " INTEGER," +
288                   Mms.CONTENT_CLASS + " INTEGER," +
289                   Mms.RESPONSE_TEXT + " TEXT," +
290                   Mms.DELIVERY_TIME + " INTEGER," +
291                   Mms.DELIVERY_REPORT + " INTEGER);");
292
293        db.execSQL("CREATE TABLE " + MmsProvider.TABLE_ADDR + " (" +
294                   Addr._ID + " INTEGER PRIMARY KEY," +
295                   Addr.MSG_ID + " INTEGER," +
296                   Addr.CONTACT_ID + " INTEGER," +
297                   Addr.ADDRESS + " TEXT," +
298                   Addr.TYPE + " INTEGER," +
299                   Addr.CHARSET + " INTEGER);");
300
301        db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PART + " (" +
302                   Part._ID + " INTEGER PRIMARY KEY," +
303                   Part.MSG_ID + " INTEGER," +
304                   Part.SEQ + " INTEGER DEFAULT 0," +
305                   Part.CONTENT_TYPE + " TEXT," +
306                   Part.NAME + " TEXT," +
307                   Part.CHARSET + " INTEGER," +
308                   Part.CONTENT_DISPOSITION + " TEXT," +
309                   Part.FILENAME + " TEXT," +
310                   Part.CONTENT_ID + " TEXT," +
311                   Part.CONTENT_LOCATION + " TEXT," +
312                   Part.CT_START + " INTEGER," +
313                   Part.CT_TYPE + " TEXT," +
314                   Part._DATA + " TEXT);");
315
316        db.execSQL("CREATE TABLE " + MmsProvider.TABLE_RATE + " (" +
317                   Rate.SENT_TIME + " INTEGER);");
318
319        db.execSQL("CREATE TABLE " + MmsProvider.TABLE_DRM + " (" +
320                   BaseColumns._ID + " INTEGER PRIMARY KEY," +
321                   "_data TEXT);");
322    }
323
324    private void createMmsTriggers(SQLiteDatabase db) {
325        // Cleans up parts when a MM is deleted.
326        db.execSQL("CREATE TRIGGER part_cleanup DELETE ON " + MmsProvider.TABLE_PDU + " " +
327                   "BEGIN " +
328                   "  DELETE FROM " + MmsProvider.TABLE_PART +
329                   "  WHERE " + Part.MSG_ID + "=old._id;" +
330                   "END;");
331
332        // Cleans up address info when a MM is deleted.
333        db.execSQL("CREATE TRIGGER addr_cleanup DELETE ON " + MmsProvider.TABLE_PDU + " " +
334                   "BEGIN " +
335                   "  DELETE FROM " + MmsProvider.TABLE_ADDR +
336                   "  WHERE " + Addr.MSG_ID + "=old._id;" +
337                   "END;");
338
339        // Delete obsolete delivery-report, read-report while deleting their
340        // associated Send.req.
341        db.execSQL("CREATE TRIGGER cleanup_delivery_and_read_report " +
342                   "AFTER DELETE ON " + MmsProvider.TABLE_PDU + " " +
343                   "WHEN old." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_SEND_REQ + " " +
344                   "BEGIN " +
345                   "  DELETE FROM " + MmsProvider.TABLE_PDU +
346                   "  WHERE (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_DELIVERY_IND +
347                   "    OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_READ_ORIG_IND + ")" +
348                   "    AND " + Mms.MESSAGE_ID + "=old." + Mms.MESSAGE_ID + "; " +
349                   "END;");
350    }
351
352    private void createSmsTables(SQLiteDatabase db) {
353        // N.B.: Whenever the columns here are changed, the columns in
354        // {@ref MmsSmsProvider} must be changed to match.
355        db.execSQL("CREATE TABLE sms (" +
356                   "_id INTEGER PRIMARY KEY," +
357                   "thread_id INTEGER," +
358                   "address TEXT," +
359                   "person INTEGER," +
360                   "date INTEGER," +
361                   "protocol INTEGER," +
362                   "read INTEGER DEFAULT 0," +
363                   "status INTEGER DEFAULT -1," + // a TP-Status value
364                                                  // or -1 if it
365                                                  // status hasn't
366                                                  // been received
367                   "type INTEGER," +
368                   "reply_path_present INTEGER," +
369                   "subject TEXT," +
370                   "body TEXT," +
371                   "service_center TEXT);");
372
373        /**
374         * This table is used by the SMS dispatcher to hold
375         * incomplete partial messages until all the parts arrive.
376         */
377        db.execSQL("CREATE TABLE raw (" +
378                   "_id INTEGER PRIMARY KEY," +
379                   "date INTEGER," +
380                   "reference_number INTEGER," + // one per full message
381                   "count INTEGER," + // the number of parts
382                   "sequence INTEGER," + // the part number of this message
383                   "destination_port INTEGER," +
384                   "address TEXT," +
385                   "pdu TEXT);"); // the raw PDU for this part
386
387        db.execSQL("CREATE TABLE attachments (" +
388                   "sms_id INTEGER," +
389                   "content_url TEXT," +
390                   "offset INTEGER);");
391
392        /**
393         * This table is used by the SMS dispatcher to hold pending
394         * delivery status report intents.
395         */
396        db.execSQL("CREATE TABLE sr_pending (" +
397                   "reference_number INTEGER," +
398                   "action TEXT," +
399                   "data TEXT);");
400    }
401
402    private void createCommonTables(SQLiteDatabase db) {
403        // TODO Ensure that each entry is removed when the last use of
404        // any address equivalent to its address is removed.
405
406        /**
407         * This table maps the first instance seen of any particular
408         * MMS/SMS address to an ID, which is then used as its
409         * canonical representation.  If the same address or an
410         * equivalent address (as determined by our Sqlite
411         * PHONE_NUMBERS_EQUAL extension) is seen later, this same ID
412         * will be used.
413         */
414        db.execSQL("CREATE TABLE canonical_addresses (" +
415                   "_id INTEGER PRIMARY KEY," +
416                   "address TEXT);");
417
418        /**
419         * This table maps the subject and an ordered set of recipient
420         * IDs, separated by spaces, to a unique thread ID.  The IDs
421         * come from the canonical_addresses table.  This works
422         * because messages are considered to be part of the same
423         * thread if they have the same subject (or a null subject)
424         * and the same set of recipients.
425         */
426        db.execSQL("CREATE TABLE threads (" +
427                   Threads._ID + " INTEGER PRIMARY KEY," +
428                   Threads.DATE + " INTEGER DEFAULT 0," +
429                   Threads.MESSAGE_COUNT + " INTEGER DEFAULT 0," +
430                   Threads.RECIPIENT_IDS + " TEXT," +
431                   Threads.SNIPPET + " TEXT," +
432                   Threads.SNIPPET_CHARSET + " INTEGER DEFAULT 0," +
433                   Threads.READ + " INTEGER DEFAULT 1," +
434                   Threads.TYPE + " INTEGER DEFAULT 0," +
435                   Threads.ERROR + " INTEGER DEFAULT 0);");
436
437        /**
438         * This table stores the queue of messages to be sent/downloaded.
439         */
440        db.execSQL("CREATE TABLE " + MmsSmsProvider.TABLE_PENDING_MSG +" (" +
441                   PendingMessages._ID + " INTEGER PRIMARY KEY," +
442                   PendingMessages.PROTO_TYPE + " INTEGER," +
443                   PendingMessages.MSG_ID + " INTEGER," +
444                   PendingMessages.MSG_TYPE + " INTEGER," +
445                   PendingMessages.ERROR_TYPE + " INTEGER," +
446                   PendingMessages.ERROR_CODE + " INTEGER," +
447                   PendingMessages.RETRY_INDEX + " INTEGER NOT NULL DEFAULT 0," +
448                   PendingMessages.DUE_TIME + " INTEGER," +
449                   PendingMessages.LAST_TRY + " INTEGER);");
450
451    }
452
453    // TODO Check the query plans for these triggers.
454    private void createCommonTriggers(SQLiteDatabase db) {
455        // Updates threads table whenever a message is added to pdu.
456        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON " +
457                   MmsProvider.TABLE_PDU + " " +
458                   PDU_UPDATE_THREAD_CONSTRAINTS +
459                   PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
460
461        // Updates threads table whenever a message is added to sms.
462        db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
463                   SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
464
465        // Updates threads table whenever a message in pdu is updated.
466        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
467                   "  UPDATE OF " + Mms.DATE + ", " + Mms.SUBJECT + ", " + Mms.MESSAGE_BOX +
468                   "  ON " + MmsProvider.TABLE_PDU + " " +
469                   PDU_UPDATE_THREAD_CONSTRAINTS +
470                   PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
471
472        // Updates threads table whenever a message in sms is updated.
473        db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
474                   "  UPDATE OF " + Sms.DATE + ", " + Sms.BODY + ", " + Sms.TYPE +
475                   "  ON sms " +
476                   SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
477
478        // Updates threads table whenever a message in pdu is updated.
479        db.execSQL("CREATE TRIGGER pdu_update_thread_read_on_update AFTER" +
480                   "  UPDATE OF " + Mms.READ +
481                   "  ON " + MmsProvider.TABLE_PDU + " " +
482                   PDU_UPDATE_THREAD_CONSTRAINTS +
483                   "BEGIN " +
484                   PDU_UPDATE_THREAD_READ_BODY +
485                   "END;");
486
487        // Updates threads table whenever a message in sms is updated.
488        db.execSQL("CREATE TRIGGER sms_update_thread_read_on_update AFTER" +
489                   "  UPDATE OF " + Sms.READ +
490                   "  ON sms " +
491                   "BEGIN " +
492                   SMS_UPDATE_THREAD_READ_BODY +
493                   "END;");
494
495        // Update threads table whenever a message in pdu is deleted
496        db.execSQL("CREATE TRIGGER pdu_update_thread_on_delete " +
497                   "AFTER DELETE ON pdu " +
498                   "BEGIN " +
499                   "  UPDATE threads SET " +
500                   "     date = (strftime('%s','now') * 1000)" +
501                   "  WHERE threads._id = old." + Mms.THREAD_ID + "; " +
502                   UPDATE_THREAD_COUNT_ON_OLD +
503                   UPDATE_THREAD_SNIPPET_SNIPPET_CS_ON_DELETE +
504                   "END;");
505
506        // When the last message in a thread is deleted, these
507        // triggers ensure that the entry for its thread ID is removed
508        // from the threads table.
509        db.execSQL("CREATE TRIGGER delete_obsolete_threads_pdu " +
510                   "AFTER DELETE ON pdu " +
511                   "BEGIN " +
512                   "  DELETE FROM threads " +
513                   "  WHERE " +
514                   "    _id = old.thread_id " +
515                   "    AND _id NOT IN " +
516                   "    (SELECT thread_id FROM sms " +
517                   "     UNION SELECT thread_id from pdu); " +
518                   "END;");
519
520        db.execSQL("CREATE TRIGGER delete_obsolete_threads_when_update_pdu " +
521                   "AFTER UPDATE OF " + Mms.THREAD_ID + " ON pdu " +
522                   "WHEN old." + Mms.THREAD_ID + " != new." + Mms.THREAD_ID + " " +
523                   "BEGIN " +
524                   "  DELETE FROM threads " +
525                   "  WHERE " +
526                   "    _id = old.thread_id " +
527                   "    AND _id NOT IN " +
528                   "    (SELECT thread_id FROM sms " +
529                   "     UNION SELECT thread_id from pdu); " +
530                   "END;");
531        // Insert pending status for M-Notification.ind or M-ReadRec.ind
532        // when they are inserted into Inbox/Outbox.
533        db.execSQL("CREATE TRIGGER insert_mms_pending_on_insert " +
534                   "AFTER INSERT ON pdu " +
535                   "WHEN new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND +
536                   "  OR new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_READ_REC_IND + " " +
537                   "BEGIN " +
538                   "  INSERT INTO " + MmsSmsProvider.TABLE_PENDING_MSG +
539                   "    (" + PendingMessages.PROTO_TYPE + "," +
540                   "     " + PendingMessages.MSG_ID + "," +
541                   "     " + PendingMessages.MSG_TYPE + "," +
542                   "     " + PendingMessages.ERROR_TYPE + "," +
543                   "     " + PendingMessages.ERROR_CODE + "," +
544                   "     " + PendingMessages.RETRY_INDEX + "," +
545                   "     " + PendingMessages.DUE_TIME + ") " +
546                   "  VALUES " +
547                   "    (" + MmsSms.MMS_PROTO + "," +
548                   "      new." + BaseColumns._ID + "," +
549                   "      new." + Mms.MESSAGE_TYPE + ",0,0,0,0);" +
550                   "END;");
551
552        // Insert pending status for M-Send.req when it is moved into Outbox.
553        db.execSQL("CREATE TRIGGER insert_mms_pending_on_update " +
554                   "AFTER UPDATE ON pdu " +
555                   "WHEN new." + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_SEND_REQ +
556                   "  AND new." + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_OUTBOX +
557                   "  AND old." + Mms.MESSAGE_BOX + "!=" + Mms.MESSAGE_BOX_OUTBOX + " " +
558                   "BEGIN " +
559                   "  INSERT INTO " + MmsSmsProvider.TABLE_PENDING_MSG +
560                   "    (" + PendingMessages.PROTO_TYPE + "," +
561                   "     " + PendingMessages.MSG_ID + "," +
562                   "     " + PendingMessages.MSG_TYPE + "," +
563                   "     " + PendingMessages.ERROR_TYPE + "," +
564                   "     " + PendingMessages.ERROR_CODE + "," +
565                   "     " + PendingMessages.RETRY_INDEX + "," +
566                   "     " + PendingMessages.DUE_TIME + ") " +
567                   "  VALUES " +
568                   "    (" + MmsSms.MMS_PROTO + "," +
569                   "      new." + BaseColumns._ID + "," +
570                   "      new." + Mms.MESSAGE_TYPE + ",0,0,0,0);" +
571                   "END;");
572
573        // When a message is moved out of Outbox, delete its pending status.
574        db.execSQL("CREATE TRIGGER delete_mms_pending_on_update " +
575                   "AFTER UPDATE ON " + MmsProvider.TABLE_PDU + " " +
576                   "WHEN old." + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_OUTBOX +
577                   "  AND new." + Mms.MESSAGE_BOX + "!=" + Mms.MESSAGE_BOX_OUTBOX + " " +
578                   "BEGIN " +
579                   "  DELETE FROM " + MmsSmsProvider.TABLE_PENDING_MSG +
580                   "  WHERE " + PendingMessages.MSG_ID + "=new._id; " +
581                   "END;");
582
583        // Delete pending status for a message when it is deleted.
584        db.execSQL("CREATE TRIGGER delete_mms_pending_on_delete " +
585                   "AFTER DELETE ON " + MmsProvider.TABLE_PDU + " " +
586                   "BEGIN " +
587                   "  DELETE FROM " + MmsSmsProvider.TABLE_PENDING_MSG +
588                   "  WHERE " + PendingMessages.MSG_ID + "=old._id; " +
589                   "END;");
590
591        // TODO Add triggers for SMS retry-status management.
592
593        // Update the error flag of threads when the error type of
594        // a pending MM is updated.
595        db.execSQL("CREATE TRIGGER update_threads_error_on_update_mms " +
596                   "  AFTER UPDATE OF err_type ON pending_msgs " +
597                   "  WHEN (OLD.err_type < 10 AND NEW.err_type >= 10)" +
598                   "    OR (OLD.err_type >= 10 AND NEW.err_type < 10) " +
599                   "BEGIN" +
600                   "  UPDATE threads SET error = " +
601                   "    CASE" +
602                   "      WHEN NEW.err_type >= 10 THEN error + 1" +
603                   "      ELSE error - 1" +
604                   "    END " +
605                   "  WHERE _id =" +
606                   "   (SELECT DISTINCT thread_id" +
607                   "    FROM pdu" +
608                   "    WHERE _id = NEW.msg_id); " +
609                   "END;");
610
611        // Update the error flag of threads when delete pending message.
612        db.execSQL("CREATE TRIGGER update_threads_error_on_delete_mms " +
613                   "  BEFORE DELETE ON pdu" +
614                   "  WHEN OLD._id IN (SELECT DISTINCT msg_id" +
615                   "                   FROM pending_msgs" +
616                   "                   WHERE err_type >= 10) " +
617                   "BEGIN " +
618                   "  UPDATE threads SET error = error - 1" +
619                   "  WHERE _id = OLD.thread_id; " +
620                   "END;");
621
622        // Update the error flag of threads while moving an MM out of Outbox,
623        // which was failed to be sent permanently.
624        db.execSQL("CREATE TRIGGER update_threads_error_on_move_mms " +
625                   "  BEFORE UPDATE OF msg_box ON pdu " +
626                   "  WHEN (OLD.msg_box = 4 AND NEW.msg_box != 4) " +
627                   "  AND (OLD._id IN (SELECT DISTINCT msg_id" +
628                   "                   FROM pending_msgs" +
629                   "                   WHERE err_type >= 10)) " +
630                   "BEGIN " +
631                   "  UPDATE threads SET error = error - 1" +
632                   "  WHERE _id = OLD.thread_id; " +
633                   "END;");
634
635        // Update the error flag of threads after a text message was
636        // failed to send/receive.
637        db.execSQL("CREATE TRIGGER update_threads_error_on_update_sms " +
638                   "  AFTER UPDATE OF type ON sms" +
639                   "  WHEN (OLD.type != 5 AND NEW.type = 5)" +
640                   "    OR (OLD.type = 5 AND NEW.type != 5) " +
641                   "BEGIN " +
642                   "  UPDATE threads SET error = " +
643                   "    CASE" +
644                   "      WHEN NEW.type = 5 THEN error + 1" +
645                   "      ELSE error - 1" +
646                   "    END " +
647                   "  WHERE _id = NEW.thread_id; " +
648                   "END;");
649    }
650
651    @Override
652    public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
653        Log.w(TAG, "Upgrading database from version " + oldVersion
654                + " to " + currentVersion + ".");
655
656        switch (oldVersion) {
657            case 24:
658                if (currentVersion <= 24) {
659                    return;
660                }
661
662                db.beginTransaction();
663                try {
664                    upgradeDatabaseToVersion25(db);
665                    db.setTransactionSuccessful();
666                } catch (Throwable ex) {
667                    Log.e(TAG, ex.getMessage(), ex);
668                    break; // force to destroy all old data;
669                } finally {
670                    db.endTransaction();
671                }
672                // fall-through
673            case 25:
674                if (currentVersion <= 25) {
675                    return;
676                }
677
678                db.beginTransaction();
679                try {
680                    upgradeDatabaseToVersion26(db);
681                    db.setTransactionSuccessful();
682                } catch (Throwable ex) {
683                    Log.e(TAG, ex.getMessage(), ex);
684                    break; // force to destroy all old data;
685                } finally {
686                    db.endTransaction();
687                }
688                // fall-through
689            case 26:
690                if (currentVersion <= 26) {
691                    return;
692                }
693
694                db.beginTransaction();
695                try {
696                    upgradeDatabaseToVersion27(db);
697                    db.setTransactionSuccessful();
698                } catch (Throwable ex) {
699                    Log.e(TAG, ex.getMessage(), ex);
700                    break; // force to destroy all old data;
701                } finally {
702                    db.endTransaction();
703                }
704                // fall-through
705            case 27:
706                if (currentVersion <= 27) {
707                    return;
708                }
709
710                db.beginTransaction();
711                try {
712                    upgradeDatabaseToVersion28(db);
713                    db.setTransactionSuccessful();
714                } catch (Throwable ex) {
715                    Log.e(TAG, ex.getMessage(), ex);
716                    break; // force to destroy all old data;
717                } finally {
718                    db.endTransaction();
719                }
720                // fall-through
721            case 28:
722                if (currentVersion <= 28) {
723                    return;
724                }
725
726                // Test whether this database file is from TC2 branch.
727                Cursor c = db.rawQuery("SELECT * FROM threads", null);
728                if (c != null) {
729                    try {
730                        c.getColumnIndexOrThrow("snippet_cs");
731                    } catch (IllegalArgumentException e) {
732                        // Column 'snippet_cs' doesn't exist, which means
733                        // this database file was maintained by TC2 branch
734                        // and its version is inconsistent.
735                        Log.w(TAG, "Upgrade database file from TC2!!!");
736                        db.beginTransaction();
737                        try {
738                            upgradeDatabaseToVersion28(db);
739                            db.setTransactionSuccessful();
740                        } catch (Throwable ex) {
741                            Log.e(TAG, ex.getMessage(), ex);
742                            break; // force to destroy all old data;
743                        } finally {
744                            db.endTransaction();
745                        }
746                    } finally {
747                        c.close();
748                    }
749                }
750
751                db.beginTransaction();
752                try {
753                    upgradeDatabaseToVersion29(db);
754                    db.setTransactionSuccessful();
755                } catch (Throwable ex) {
756                    Log.e(TAG, ex.getMessage(), ex);
757                    break; // force to destroy all old data;
758                } finally {
759                    db.endTransaction();
760                }
761                // fall-through
762            case 29:
763                if (currentVersion <= 29) {
764                    return;
765                }
766
767                db.beginTransaction();
768                try {
769                    upgradeDatabaseToVersion30(db);
770                    db.setTransactionSuccessful();
771                } catch (Throwable ex) {
772                    Log.e(TAG, ex.getMessage(), ex);
773                    break; // force to destroy all old data;
774                } finally {
775                    db.endTransaction();
776                }
777                // fall-through
778            case 30:
779                if (currentVersion <= 30) {
780                    return;
781                }
782
783                db.beginTransaction();
784                try {
785                    upgradeDatabaseToVersion31(db);
786                    db.setTransactionSuccessful();
787                } catch (Throwable ex) {
788                    Log.e(TAG, ex.getMessage(), ex);
789                    break; // force to destroy all old data;
790                } finally {
791                    db.endTransaction();
792                }
793                // fall-through
794            case 31:
795                if (currentVersion <= 31) {
796                    return;
797                }
798
799                db.beginTransaction();
800                try {
801                    upgradeDatabaseToVersion32(db);
802                    db.setTransactionSuccessful();
803                } catch (Throwable ex) {
804                    Log.e(TAG, ex.getMessage(), ex);
805                    break; // force to destroy all old data;
806                } finally {
807                    db.endTransaction();
808                }
809                // fall-through
810            case 32:
811                if (currentVersion <= 32) {
812                    return;
813                }
814
815                db.beginTransaction();
816                try {
817                    upgradeDatabaseToVersion33(db);
818                    db.setTransactionSuccessful();
819                } catch (Throwable ex) {
820                    Log.e(TAG, ex.getMessage(), ex);
821                    break; // force to destroy all old data;
822                } finally {
823                    db.endTransaction();
824                }
825                // fall-through
826            case 33:
827                if (currentVersion <= 33) {
828                    return;
829                }
830
831                db.beginTransaction();
832                try {
833                    upgradeDatabaseToVersion34(db);
834                    db.setTransactionSuccessful();
835                } catch (Throwable ex) {
836                    Log.e(TAG, ex.getMessage(), ex);
837                    break; // force to destroy all old data;
838                } finally {
839                    db.endTransaction();
840                }
841                // fall-through
842            case 34:
843                if (currentVersion <= 34) {
844                    return;
845                }
846
847                db.beginTransaction();
848                try {
849                    upgradeDatabaseToVersion35(db);
850                    db.setTransactionSuccessful();
851                } catch (Throwable ex) {
852                    Log.e(TAG, ex.getMessage(), ex);
853                    break; // force to destroy all old data;
854                } finally {
855                    db.endTransaction();
856                }
857                // fall-through
858            case 35:
859                if (currentVersion <= 35) {
860                    return;
861                }
862
863                db.beginTransaction();
864                try {
865                    upgradeDatabaseToVersion36(db);
866                    db.setTransactionSuccessful();
867                } catch (Throwable ex) {
868                    Log.e(TAG, ex.getMessage(), ex);
869                    break; // force to destroy all old data;
870                } finally {
871                    db.endTransaction();
872                }
873                // fall-through
874            case 36:
875                if (currentVersion <= 36) {
876                    return;
877                }
878
879                db.beginTransaction();
880                try {
881                    upgradeDatabaseToVersion37(db);
882                    db.setTransactionSuccessful();
883                } catch (Throwable ex) {
884                    Log.e(TAG, ex.getMessage(), ex);
885                    break; // force to destroy all old data;
886                } finally {
887                    db.endTransaction();
888                }
889                // fall-through
890            case 37:
891                if (currentVersion <= 37) {
892                    return;
893                }
894
895                db.beginTransaction();
896                try {
897                    upgradeDatabaseToVersion38(db);
898                    db.setTransactionSuccessful();
899                } catch (Throwable ex) {
900                    Log.e(TAG, ex.getMessage(), ex);
901                    break; // force to destroy all old data;
902                } finally {
903                    db.endTransaction();
904                }
905                // fall-through
906            case 38:
907                if (currentVersion <= 38) {
908                    return;
909                }
910
911                db.beginTransaction();
912                try {
913                    upgradeDatabaseToVersion39(db);
914                    db.setTransactionSuccessful();
915                } catch (Throwable ex) {
916                    Log.e(TAG, ex.getMessage(), ex);
917                    break; // force to destroy all old data;
918                } finally {
919                    db.endTransaction();
920                }
921                // fall-through
922            case 39:
923                if (currentVersion <= 39) {
924                    return;
925                }
926
927                db.beginTransaction();
928                try {
929                    upgradeDatabaseToVersion40(db);
930                    db.setTransactionSuccessful();
931                } catch (Throwable ex) {
932                    Log.e(TAG, ex.getMessage(), ex);
933                    break; // force to destroy all old data;
934                } finally {
935                    db.endTransaction();
936                }
937                // fall-through
938            case 40:
939                if (currentVersion <= 40) {
940                    return;
941                }
942
943                db.beginTransaction();
944                try {
945                    upgradeDatabaseToVersion41(db);
946                    db.setTransactionSuccessful();
947                } catch (Throwable ex) {
948                    Log.e(TAG, ex.getMessage(), ex);
949                    break; // force to destroy all old data;
950                } finally {
951                    db.endTransaction();
952                }
953                // fall-through
954            case 41:
955                if (currentVersion <= 41) {
956                    return;
957                }
958                db.beginTransaction();
959                try {
960                    upgradeDatabaseToVersion42(db);
961                    db.setTransactionSuccessful();
962                } catch (Throwable ex) {
963                    Log.e(TAG, ex.getMessage(), ex);
964                    break;
965                } finally {
966                    db.endTransaction();
967                }
968                return;
969        }
970
971        Log.w(TAG, "Destroying all old data.");
972        dropCommonTriggers(db);
973        dropMmsTriggers(db);
974        dropCommonTables(db);
975        dropMmsTables(db);
976        dropSmsTables(db);
977        onCreate(db);
978    }
979
980    private void dropCommonTables(SQLiteDatabase db) {
981        db.execSQL("DROP TABLE IF EXISTS canonical_addresses");
982        db.execSQL("DROP TABLE IF EXISTS threads");
983        db.execSQL("DROP TABLE IF EXISTS " + MmsSmsProvider.TABLE_PENDING_MSG);
984    }
985
986    private void dropCommonTriggers(SQLiteDatabase db) {
987        db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_pdu");
988        db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_when_update_pdu");
989        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
990        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_insert");
991        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
992        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_date_subject_on_update");
993        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_read_on_update");
994        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_read_on_update");
995        db.execSQL("DROP TRIGGER IF EXISTS insert_mms_pending_on_insert");
996        db.execSQL("DROP TRIGGER IF EXISTS insert_mms_pending_on_update");
997        db.execSQL("DROP TRIGGER IF EXISTS delete_mms_pending_on_update");
998        db.execSQL("DROP TRIGGER IF EXISTS delete_mms_pending_on_delete");
999        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_update_mms");
1000        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete_mms");
1001        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_move_mms");
1002        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_update_sms");
1003    }
1004
1005    private void dropSmsTables(SQLiteDatabase db) {
1006        db.execSQL("DROP TABLE IF EXISTS sms");
1007        db.execSQL("DROP TABLE IF EXISTS newSmsIndicator");
1008        db.execSQL("DROP TABLE IF EXISTS raw");
1009        db.execSQL("DROP TABLE IF EXISTS attachments");
1010        db.execSQL("DROP TABLE IF EXISTS thread_ids");
1011        db.execSQL("DROP TABLE IF EXISTS sr_pending");
1012    }
1013
1014    private void dropMmsTables(SQLiteDatabase db) {
1015        db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_PDU + ";");
1016        db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_ADDR + ";");
1017        db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_PART + ";");
1018        db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_RATE + ";");
1019        db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_DRM + ";");
1020    }
1021
1022    private void dropMmsTriggers(SQLiteDatabase db) {
1023        db.execSQL("DROP TRIGGER IF EXISTS part_cleanup;");
1024        db.execSQL("DROP TRIGGER IF EXISTS addr_cleanup;");
1025        db.execSQL("DROP TRIGGER IF EXISTS cleanup_delivery_and_read_report;");
1026    }
1027
1028    private void upgradeDatabaseToVersion25(SQLiteDatabase db) {
1029        db.execSQL("ALTER TABLE threads " +
1030                   "ADD COLUMN type INTEGER NOT NULL DEFAULT 0;");
1031    }
1032
1033    private void upgradeDatabaseToVersion26(SQLiteDatabase db) {
1034        db.execSQL("ALTER TABLE threads " +
1035                   "ADD COLUMN error INTEGER DEFAULT 0;");
1036
1037        // Do NOT use defined symbols when upgrading database
1038        // because they may be changed and cannot be applied
1039        // to old database.
1040        db.execSQL("UPDATE threads SET error = 1 WHERE _id IN" +
1041                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1042                   "     ON pdu.thread_id = pending_msgs.msg_id" +
1043                   "     WHERE proto_type = 1 AND err_type >= 10" +
1044                   "     GROUP BY thread_id); " +
1045                   "UPDATE threads SET error = 1 WHERE _id IN" +
1046                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1047                   "     ON sms.thread_id = pending_msgs.msg_id" +
1048                   "     WHERE proto_type = 0 AND err_type >= 10" +
1049                   "     GROUP BY thread_id); ");
1050
1051        db.execSQL("CREATE TRIGGER update_threads_error_on_update " +
1052                   "  AFTER UPDATE OF err_type ON pending_msgs " +
1053                   "BEGIN " +
1054                   "UPDATE threads SET error = 1 WHERE _id IN" +
1055                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1056                   "     ON pdu.thread_id = pending_msgs.msg_id" +
1057                   "     WHERE proto_type = 1 AND err_type >= 10" +
1058                   "     GROUP BY thread_id); " +
1059                   "UPDATE threads SET error = 1 WHERE _id IN" +
1060                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1061                   "     ON sms.thread_id = pending_msgs.msg_id" +
1062                   "     WHERE proto_type = 0 AND err_type >= 10" +
1063                   "     GROUP BY thread_id); " +
1064                   "END;");
1065
1066        db.execSQL("CREATE TRIGGER update_threads_error_on_delete " +
1067                   "  AFTER DELETE ON pending_msgs " +
1068                   "BEGIN " +
1069                   "UPDATE threads SET error = 1 WHERE _id IN" +
1070                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1071                   "     ON pdu.thread_id = pending_msgs.msg_id" +
1072                   "     WHERE proto_type = 1 AND err_type >= 10" +
1073                   "     GROUP BY thread_id); " +
1074                   "UPDATE threads SET error = 1 WHERE _id IN" +
1075                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1076                   "     ON sms.thread_id = pending_msgs.msg_id" +
1077                   "     WHERE proto_type = 0 AND err_type >= 10" +
1078                   "     GROUP BY thread_id); " +
1079                   "END;");
1080    }
1081
1082    private void upgradeDatabaseToVersion27(SQLiteDatabase db) {
1083        db.execSQL("UPDATE threads SET error = 1 WHERE _id IN" +
1084                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1085                   "     ON pdu._id = pending_msgs.msg_id" +
1086                   "     WHERE proto_type = 1 AND err_type >= 10" +
1087                   "     GROUP BY thread_id); " +
1088                   "UPDATE threads SET error = 1 WHERE _id IN" +
1089                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1090                   "     ON sms._id = pending_msgs.msg_id" +
1091                   "     WHERE proto_type = 0 AND err_type >= 10" +
1092                   "     GROUP BY thread_id); ");
1093
1094        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_update");
1095        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete");
1096
1097        db.execSQL("CREATE TRIGGER update_threads_error_on_update " +
1098                   "  AFTER UPDATE OF err_type ON pending_msgs " +
1099                   "BEGIN " +
1100                   "UPDATE threads SET error = 1 WHERE _id IN" +
1101                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1102                   "     ON pdu._id = pending_msgs.msg_id" +
1103                   "     WHERE proto_type = 1 AND err_type >= 10" +
1104                   "     GROUP BY thread_id); " +
1105                   "UPDATE threads SET error = 1 WHERE _id IN" +
1106                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1107                   "     ON sms._id = pending_msgs.msg_id" +
1108                   "     WHERE proto_type = 0 AND err_type >= 10" +
1109                   "     GROUP BY thread_id); " +
1110                   "END;");
1111
1112        db.execSQL("CREATE TRIGGER update_threads_error_on_delete " +
1113                   "  AFTER DELETE ON pending_msgs " +
1114                   "BEGIN " +
1115                   "UPDATE threads SET error = 1 WHERE _id IN" +
1116                   "  (SELECT thread_id FROM pdu LEFT JOIN pending_msgs" +
1117                   "     ON pdu._id = pending_msgs.msg_id" +
1118                   "     WHERE proto_type = 1 AND err_type >= 10" +
1119                   "     GROUP BY thread_id); " +
1120                   "UPDATE threads SET error = 1 WHERE _id IN" +
1121                   "  (SELECT thread_id FROM sms LEFT JOIN pending_msgs" +
1122                   "     ON sms._id = pending_msgs.msg_id" +
1123                   "     WHERE proto_type = 0 AND err_type >= 10" +
1124                   "     GROUP BY thread_id); " +
1125                   "END;");
1126    }
1127
1128    private void upgradeDatabaseToVersion28(SQLiteDatabase db) {
1129        db.execSQL("ALTER TABLE threads " +
1130                   "ADD COLUMN snippet_cs INTEGER NOT NULL DEFAULT 0;");
1131
1132        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
1133        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
1134        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_read_on_update");
1135        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
1136
1137        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON pdu " +
1138                   "  WHEN new.msg_box!=5 AND new.msg_box!=3" +
1139                   "    AND (new.m_type=132 OR new.m_type=130 OR new.m_type=128) " +
1140                   "BEGIN" +
1141                   "  UPDATE threads SET" +
1142                   "    date = (strftime('%s','now') * 1000), " +
1143                   "    snippet = new.sub, " +
1144                   "    snippet_cs = new.sub_cs" +
1145                   "  WHERE threads._id = new.thread_id; " +
1146                   "  UPDATE threads SET read = " +
1147                   "    CASE (SELECT COUNT(*)" +
1148                   "          FROM pdu" +
1149                   "          WHERE read = 0 AND thread_id = threads._id)" +
1150                   "      WHEN 0 THEN 1 ELSE 0" +
1151                   "    END" +
1152                   "  WHERE threads._id = new.thread_id; " +
1153                   "END;");
1154
1155        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
1156                   "  UPDATE OF date, sub, msg_box ON pdu " +
1157                   "  WHEN new.msg_box!=5 AND new.msg_box!=3" +
1158                   "    AND (new.m_type=132 OR new.m_type=130 OR new.m_type=128) " +
1159                   "BEGIN" +
1160                   "  UPDATE threads SET" +
1161                   "    date = (strftime('%s','now') * 1000), " +
1162                   "    snippet = new.sub, " +
1163                   "    snippet_cs = new.sub_cs" +
1164                   "  WHERE threads._id = new.thread_id; " +
1165                   "  UPDATE threads SET read = " +
1166                   "    CASE (SELECT COUNT(*)" +
1167                   "          FROM pdu" +
1168                   "          WHERE read = 0 AND thread_id = threads._id)" +
1169                   "      WHEN 0 THEN 1 ELSE 0" +
1170                   "    END" +
1171                   "  WHERE threads._id = new.thread_id; " +
1172                   "END;");
1173
1174        db.execSQL("CREATE TRIGGER pdu_update_thread_read_on_update AFTER" +
1175                   "  UPDATE OF read ON pdu " +
1176                   "  WHEN new.msg_box!=5 AND new.msg_box!=3" +
1177                   "    AND (new.m_type=132 OR new.m_type=130 OR new.m_type=128) " +
1178                   "BEGIN " +
1179                   "  UPDATE threads SET read = " +
1180                   "    CASE (SELECT COUNT(*)" +
1181                   "          FROM pdu" +
1182                   "          WHERE read = 0 AND thread_id = threads._id)" +
1183                   "      WHEN 0 THEN 1 ELSE 0" +
1184                   "    END" +
1185                   "  WHERE threads._id = new.thread_id; " +
1186                   "END;");
1187
1188        db.execSQL("CREATE TRIGGER sms_update_thread_on_delete " +
1189                   "AFTER DELETE ON sms " +
1190                   "BEGIN " +
1191                   "  UPDATE threads SET " +
1192                   "     date = (strftime('%s','now') * 1000), " +
1193                   "     snippet = (SELECT body FROM SMS ORDER BY date DESC LIMIT 1)" +
1194                   "  WHERE threads._id = old.thread_id; " +
1195                   "END;");
1196    }
1197
1198    private void upgradeDatabaseToVersion29(SQLiteDatabase db) {
1199        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
1200        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
1201        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_read_on_update");
1202
1203        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON pdu " +
1204                   "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1205                   "BEGIN" +
1206                   "  UPDATE threads SET" +
1207                   "    date = (strftime('%s','now') * 1000), " +
1208                   "    snippet = new.sub, " +
1209                   "    snippet_cs = new.sub_cs" +
1210                   "  WHERE threads._id = new.thread_id; " +
1211                   "  UPDATE threads SET read = " +
1212                   "    CASE (SELECT COUNT(*)" +
1213                   "          FROM pdu" +
1214                   "          WHERE read = 0 AND thread_id = threads._id)" +
1215                   "      WHEN 0 THEN 1 ELSE 0" +
1216                   "    END" +
1217                   "  WHERE threads._id = new.thread_id; " +
1218                   "END;");
1219
1220        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
1221                   "  UPDATE OF date, sub, msg_box ON pdu " +
1222                   "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1223                   "BEGIN" +
1224                   "  UPDATE threads SET" +
1225                   "    date = (strftime('%s','now') * 1000), " +
1226                   "    snippet = new.sub, " +
1227                   "    snippet_cs = new.sub_cs" +
1228                   "  WHERE threads._id = new.thread_id; " +
1229                   "  UPDATE threads SET read = " +
1230                   "    CASE (SELECT COUNT(*)" +
1231                   "          FROM pdu" +
1232                   "          WHERE read = 0 AND thread_id = threads._id)" +
1233                   "      WHEN 0 THEN 1 ELSE 0" +
1234                   "    END" +
1235                   "  WHERE threads._id = new.thread_id; " +
1236                   "END;");
1237
1238        db.execSQL("CREATE TRIGGER pdu_update_thread_read_on_update AFTER" +
1239                   "  UPDATE OF read ON pdu " +
1240                   "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1241                   "BEGIN " +
1242                   "  UPDATE threads SET read = " +
1243                   "    CASE (SELECT COUNT(*)" +
1244                   "          FROM pdu" +
1245                   "          WHERE read = 0 AND thread_id = threads._id)" +
1246                   "      WHEN 0 THEN 1 ELSE 0" +
1247                   "    END" +
1248                   "  WHERE threads._id = new.thread_id; " +
1249                   "END;");
1250    }
1251
1252    private void upgradeDatabaseToVersion30(SQLiteDatabase db) {
1253        // Since SQLite doesn't support altering constraints
1254        // of an existing table, I have to create a new table
1255        // with updated constraints, copy old data into this
1256        // table, drop old table and then rename the new table
1257        // to 'threads'.
1258        db.execSQL("CREATE TABLE temp_threads (" +
1259                   "_id INTEGER PRIMARY KEY," +
1260                   "date INTEGER DEFAULT 0," +
1261                   "subject TEXT," +
1262                   "recipient_ids TEXT," +
1263                   "snippet TEXT," +
1264                   "snippet_cs INTEGER DEFAULT 0," +
1265                   "read INTEGER DEFAULT 1," +
1266                   "type INTEGER DEFAULT 0," +
1267                   "error INTEGER DEFAULT 0);");
1268        db.execSQL("INSERT INTO temp_threads SELECT * FROM threads;");
1269        db.execSQL("DROP TABLE IF EXISTS threads;");
1270        db.execSQL("ALTER TABLE temp_threads RENAME TO threads;");
1271    }
1272
1273    private void upgradeDatabaseToVersion31(SQLiteDatabase db) {
1274        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
1275
1276        // Update threads table whenever a message in sms is deleted
1277        // (Usually an abandoned draft.)
1278        db.execSQL("CREATE TRIGGER sms_update_thread_on_delete " +
1279                   "AFTER DELETE ON sms " +
1280                   "BEGIN " +
1281                   "  UPDATE threads SET " +
1282                   "     date = (strftime('%s','now') * 1000) " +
1283                   "  WHERE threads._id = old.thread_id; " +
1284                   "  UPDATE threads SET" +
1285                   "    snippet = (SELECT snippet FROM" +
1286                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1287                   "         sub_cs AS snippet_cs FROM pdu" +
1288                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1289                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1290                   "  WHERE threads._id = old.thread_id; " +
1291                   "  UPDATE threads SET" +
1292                   "    snippet_cs = (SELECT snippet_cs FROM" +
1293                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1294                   "         sub_cs AS snippet_cs FROM pdu" +
1295                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1296                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1297                   "  WHERE threads._id = old.thread_id; " +
1298                   "END;");
1299
1300        // Update threads table whenever a message in pdu is deleted
1301        db.execSQL("CREATE TRIGGER pdu_update_thread_on_delete " +
1302                   "AFTER DELETE ON pdu " +
1303                   "BEGIN " +
1304                   "  UPDATE threads SET " +
1305                   "     date = (strftime('%s','now') * 1000)" +
1306                   "  WHERE threads._id = old.thread_id;" +
1307                   "  UPDATE threads SET" +
1308                   "    snippet = (SELECT snippet FROM" +
1309                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1310                   "         sub_cs AS snippet_cs FROM pdu" +
1311                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1312                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1313                   "  WHERE threads._id = old.thread_id; " +
1314                   "  UPDATE threads SET" +
1315                   "    snippet_cs = (SELECT snippet_cs FROM" +
1316                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1317                   "         sub_cs AS snippet_cs FROM pdu" +
1318                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1319                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1320                   "  WHERE threads._id = old.thread_id; " +
1321                   "END;");
1322    }
1323
1324    private void upgradeDatabaseToVersion32(SQLiteDatabase db) {
1325        db.execSQL("CREATE TABLE IF NOT EXISTS rate (sent_time INTEGER);");
1326    }
1327
1328    private void upgradeDatabaseToVersion33(SQLiteDatabase db) {
1329        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_update");
1330        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete");
1331
1332        db.execSQL("CREATE TRIGGER update_threads_error_on_update_mms " +
1333                   "  AFTER UPDATE OF err_type ON pending_msgs " +
1334                   "  WHEN (OLD.err_type < 10 AND NEW.err_type >= 10)" +
1335                   "    OR (OLD.err_type >= 10 AND NEW.err_type < 10) " +
1336                   "BEGIN" +
1337                   "  UPDATE threads SET error = " +
1338                   "    CASE" +
1339                   "      WHEN NEW.err_type >= 10 THEN error + 1" +
1340                   "      ELSE error - 1" +
1341                   "    END " +
1342                   "  WHERE _id =" +
1343                   "   (SELECT DISTINCT thread_id" +
1344                   "    FROM pdu" +
1345                   "    WHERE _id = NEW.msg_id); " +
1346                   "END;");
1347
1348        db.execSQL("CREATE TRIGGER update_threads_error_on_delete_mms " +
1349                   "  BEFORE DELETE ON pdu" +
1350                   "  WHEN OLD._id IN (SELECT DISTINCT msg_id" +
1351                   "                   FROM pending_msgs" +
1352                   "                   WHERE err_type >= 10) " +
1353                   "BEGIN " +
1354                   "  UPDATE threads SET error = error - 1" +
1355                   "  WHERE _id = OLD.thread_id; " +
1356                   "END;");
1357
1358        db.execSQL("CREATE TRIGGER update_threads_error_on_update_sms " +
1359                   "  AFTER UPDATE OF type ON sms" +
1360                   "  WHEN (OLD.type != 5 AND NEW.type = 5)" +
1361                   "    OR (OLD.type = 5 AND NEW.type != 5) " +
1362                   "BEGIN " +
1363                   "  UPDATE threads SET error = " +
1364                   "    CASE" +
1365                   "      WHEN NEW.type = 5 THEN error + 1" +
1366                   "      ELSE error - 1" +
1367                   "    END " +
1368                   "  WHERE _id = NEW.thread_id; " +
1369                   "END;");
1370
1371        db.execSQL("CREATE TRIGGER update_threads_error_on_delete_sms " +
1372                   "  AFTER DELETE ON sms" +
1373                   "  WHEN (OLD.type = 5) " +
1374                   "BEGIN " +
1375                   "  UPDATE threads SET error = error - 1" +
1376                   "  WHERE _id = OLD.thread_id; " +
1377                   "END;");
1378    }
1379
1380    private void upgradeDatabaseToVersion34(SQLiteDatabase db) {
1381        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_insert");
1382        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_date_subject_on_update");
1383
1384        db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
1385                   "BEGIN" +
1386                   "  UPDATE threads SET" +
1387                   "    date = (strftime('%s','now') * 1000), " +
1388                   "    snippet = new.body," +
1389                   "    snippet_cs = 0" +
1390                   "  WHERE threads._id = new.thread_id; " +
1391                   "  UPDATE threads SET read = " +
1392                   "    CASE (SELECT COUNT(*)" +
1393                   "          FROM sms" +
1394                   "          WHERE read = 0" +
1395                   "            AND thread_id = threads._id)" +
1396                   "      WHEN 0 THEN 1" +
1397                   "      ELSE 0" +
1398                   "    END" +
1399                   "  WHERE threads._id = new.thread_id; " +
1400                   "END;");
1401
1402        db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
1403                   "  UPDATE OF date, body, msg_box" +
1404                   "  ON sms " +
1405                   "BEGIN" +
1406                   "  UPDATE threads SET" +
1407                   "    date = (strftime('%s','now') * 1000), " +
1408                   "    snippet = new.body," +
1409                   "    snippet_cs = 0" +
1410                   "  WHERE threads._id = new.thread_id; " +
1411                   "  UPDATE threads SET read = " +
1412                   "    CASE (SELECT COUNT(*)" +
1413                   "          FROM sms" +
1414                   "          WHERE read = 0" +
1415                   "            AND thread_id = threads._id)" +
1416                   "      WHEN 0 THEN 1" +
1417                   "      ELSE 0" +
1418                   "    END" +
1419                   "  WHERE threads._id = new.thread_id; " +
1420                   "END;");
1421    }
1422
1423    private void upgradeDatabaseToVersion35(SQLiteDatabase db) {
1424        db.execSQL("CREATE TABLE temp_threads (" +
1425                   "_id INTEGER PRIMARY KEY," +
1426                   "date INTEGER DEFAULT 0," +
1427                   "message_count INTEGER DEFAULT 0," +
1428                   "recipient_ids TEXT," +
1429                   "snippet TEXT," +
1430                   "snippet_cs INTEGER DEFAULT 0," +
1431                   "read INTEGER DEFAULT 1," +
1432                   "type INTEGER DEFAULT 0," +
1433                   "error INTEGER DEFAULT 0);");
1434        db.execSQL("INSERT INTO temp_threads " +
1435                   "SELECT _id, date, 0 AS message_count, recipient_ids," +
1436                   "       snippet, snippet_cs, read, type, error " +
1437                   "FROM threads;");
1438        db.execSQL("DROP TABLE IF EXISTS threads;");
1439        db.execSQL("ALTER TABLE temp_threads RENAME TO threads;");
1440
1441        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
1442        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_insert");
1443        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
1444        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_delete");
1445        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_date_subject_on_update");
1446        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
1447
1448        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON pdu " +
1449                   "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1450                   "BEGIN" +
1451                   "  UPDATE threads SET" +
1452                   "    date = (strftime('%s','now') * 1000), " +
1453                   "    snippet = new.sub, " +
1454                   "    snippet_cs = new.sub_cs" +
1455                   "  WHERE threads._id = new.thread_id; " +
1456                   "  UPDATE threads SET message_count = " +
1457                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1458                   "      ON threads._id = thread_id" +
1459                   "      WHERE thread_id = new.thread_id" +
1460                   "        AND sms.type != 3) + " +
1461                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1462                   "      ON threads._id = thread_id" +
1463                   "      WHERE thread_id = new.thread_id" +
1464                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1465                   "        AND msg_box != 3) " +
1466                   "  WHERE threads._id = new.thread_id; " +
1467                   "  UPDATE threads SET read = " +
1468                   "    CASE (SELECT COUNT(*)" +
1469                   "          FROM pdu" +
1470                   "          WHERE read = 0 AND thread_id = threads._id)" +
1471                   "      WHEN 0 THEN 1 ELSE 0" +
1472                   "    END" +
1473                   "  WHERE threads._id = new.thread_id; " +
1474                   "END;");
1475
1476        db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
1477                   "BEGIN" +
1478                   "  UPDATE threads SET" +
1479                   "    date = (strftime('%s','now') * 1000), " +
1480                   "    snippet = new.body," +
1481                   "    snippet_cs = 0" +
1482                   "  WHERE threads._id = new.thread_id; " +
1483                   "  UPDATE threads SET message_count = " +
1484                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1485                   "      ON threads._id = thread_id" +
1486                   "      WHERE thread_id = new.thread_id" +
1487                   "        AND sms.type != 3) + " +
1488                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1489                   "      ON threads._id = thread_id" +
1490                   "      WHERE thread_id = new.thread_id" +
1491                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1492                   "        AND msg_box != 3) " +
1493                   "  WHERE threads._id = new.thread_id; " +
1494                   "  UPDATE threads SET read = " +
1495                   "    CASE (SELECT COUNT(*)" +
1496                   "          FROM sms" +
1497                   "          WHERE read = 0" +
1498                   "            AND thread_id = threads._id)" +
1499                   "      WHEN 0 THEN 1" +
1500                   "      ELSE 0" +
1501                   "    END" +
1502                   "  WHERE threads._id = new.thread_id; " +
1503                   "END;");
1504
1505        db.execSQL("CREATE TRIGGER sms_update_thread_on_delete " +
1506                   "AFTER DELETE ON sms " +
1507                   "BEGIN " +
1508                   "  UPDATE threads SET " +
1509                   "     date = (strftime('%s','now') * 1000) " +
1510                   "  WHERE threads._id = old.thread_id; " +
1511                   "  UPDATE threads SET message_count = " +
1512                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1513                   "      ON threads._id = thread_id" +
1514                   "      WHERE thread_id = old.thread_id" +
1515                   "        AND sms.type != 3) + " +
1516                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1517                   "      ON threads._id = thread_id" +
1518                   "      WHERE thread_id = old.thread_id" +
1519                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1520                   "        AND msg_box != 3) " +
1521                   "  WHERE threads._id = old.thread_id; " +
1522                   "  UPDATE threads SET" +
1523                   "    snippet = (SELECT snippet FROM" +
1524                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1525                   "         sub_cs AS snippet_cs FROM pdu" +
1526                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1527                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1528                   "  WHERE threads._id = old.thread_id; " +
1529                   "  UPDATE threads SET" +
1530                   "    snippet_cs = (SELECT snippet_cs FROM" +
1531                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1532                   "         sub_cs AS snippet_cs FROM pdu" +
1533                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1534                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1535                   "  WHERE threads._id = old.thread_id; " +
1536                   "END;");
1537
1538        db.execSQL("CREATE TRIGGER pdu_update_thread_on_delete " +
1539                   "AFTER DELETE ON pdu " +
1540                   "BEGIN " +
1541                   "  UPDATE threads SET " +
1542                   "     date = (strftime('%s','now') * 1000)" +
1543                   "  WHERE threads._id = old.thread_id;" +
1544                   "  UPDATE threads SET message_count = " +
1545                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1546                   "      ON threads._id = thread_id" +
1547                   "      WHERE thread_id = old.thread_id" +
1548                   "        AND sms.type != 3) + " +
1549                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1550                   "      ON threads._id = thread_id" +
1551                   "      WHERE thread_id = old.thread_id" +
1552                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1553                   "        AND msg_box != 3) " +
1554                   "  WHERE threads._id = old.thread_id; " +
1555                   "  UPDATE threads SET" +
1556                   "    snippet = (SELECT snippet FROM" +
1557                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1558                   "         sub_cs AS snippet_cs FROM pdu" +
1559                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1560                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1561                   "  WHERE threads._id = old.thread_id; " +
1562                   "  UPDATE threads SET" +
1563                   "    snippet_cs = (SELECT snippet_cs FROM" +
1564                   "      (SELECT date * 1000 AS date, sub AS snippet," +
1565                   "         sub_cs AS snippet_cs FROM pdu" +
1566                   "       UNION SELECT date, body AS snippet, NULL AS snippet_cs" +
1567                   "         FROM sms) ORDER BY date DESC LIMIT 1) " +
1568                   "  WHERE threads._id = old.thread_id; " +
1569                   "END;");
1570
1571        db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
1572                   "  UPDATE OF date, body, type" +
1573                   "  ON sms " +
1574                   "BEGIN" +
1575                   "  UPDATE threads SET" +
1576                   "    date = (strftime('%s','now') * 1000), " +
1577                   "    snippet = new.body," +
1578                   "    snippet_cs = 0" +
1579                   "  WHERE threads._id = new.thread_id; " +
1580                   "  UPDATE threads SET message_count = " +
1581                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1582                   "      ON threads._id = thread_id" +
1583                   "      WHERE thread_id = new.thread_id" +
1584                   "        AND sms.type != 3) + " +
1585                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1586                   "      ON threads._id = thread_id" +
1587                   "      WHERE thread_id = new.thread_id" +
1588                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1589                   "        AND msg_box != 3) " +
1590                   "  WHERE threads._id = new.thread_id; " +
1591                   "  UPDATE threads SET read = " +
1592                   "    CASE (SELECT COUNT(*)" +
1593                   "          FROM sms" +
1594                   "          WHERE read = 0" +
1595                   "            AND thread_id = threads._id)" +
1596                   "      WHEN 0 THEN 1" +
1597                   "      ELSE 0" +
1598                   "    END" +
1599                   "  WHERE threads._id = new.thread_id; " +
1600                   "END;");
1601
1602        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
1603                   "  UPDATE OF date, sub, msg_box ON pdu " +
1604                   "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1605                   "BEGIN" +
1606                   "  UPDATE threads SET" +
1607                   "    date = (strftime('%s','now') * 1000), " +
1608                   "    snippet = new.sub, " +
1609                   "    snippet_cs = new.sub_cs" +
1610                   "  WHERE threads._id = new.thread_id; " +
1611                   "  UPDATE threads SET message_count = " +
1612                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1613                   "      ON threads._id = thread_id" +
1614                   "      WHERE thread_id = new.thread_id" +
1615                   "        AND sms.type != 3) + " +
1616                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1617                   "      ON threads._id = thread_id" +
1618                   "      WHERE thread_id = new.thread_id" +
1619                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1620                   "        AND msg_box != 3) " +
1621                   "  WHERE threads._id = new.thread_id; " +
1622                   "  UPDATE threads SET read = " +
1623                   "    CASE (SELECT COUNT(*)" +
1624                   "          FROM pdu" +
1625                   "          WHERE read = 0 AND thread_id = threads._id)" +
1626                   "      WHEN 0 THEN 1 ELSE 0" +
1627                   "    END" +
1628                   "  WHERE threads._id = new.thread_id; " +
1629                   "END;");
1630    }
1631
1632    private void upgradeDatabaseToVersion36(SQLiteDatabase db) {
1633        db.execSQL("CREATE TABLE IF NOT EXISTS drm (_id INTEGER PRIMARY KEY, _data TEXT);");
1634        db.execSQL("CREATE TRIGGER IF NOT EXISTS drm_file_cleanup DELETE ON drm " +
1635                   "BEGIN SELECT _DELETE_FILE(old._data); END;");
1636    }
1637
1638    private void upgradeDatabaseToVersion37(SQLiteDatabase db) {
1639        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
1640        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_delete");
1641
1642        db.execSQL("CREATE TRIGGER sms_update_thread_on_delete " +
1643                   "AFTER DELETE ON sms " +
1644                   "BEGIN " +
1645                   "  UPDATE threads SET " +
1646                   "     date = (strftime('%s','now') * 1000) " +
1647                   "  WHERE threads._id = old.thread_id; " +
1648                   "  UPDATE threads SET message_count = " +
1649                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1650                   "      ON threads._id = thread_id" +
1651                   "      WHERE thread_id = old.thread_id" +
1652                   "        AND sms.type != 3) + " +
1653                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1654                   "      ON threads._id = thread_id" +
1655                   "      WHERE thread_id = old.thread_id" +
1656                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1657                   "        AND msg_box != 3) " +
1658                   "  WHERE threads._id = old.thread_id; " +
1659                   "  UPDATE threads SET snippet = " +
1660                   "   (SELECT snippet FROM" +
1661                   "     (SELECT date * 1000 AS date, sub AS snippet, thread_id FROM pdu" +
1662                   "      UNION SELECT date, body AS snippet, thread_id FROM sms)" +
1663                   "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
1664                   "  WHERE threads._id = OLD.thread_id; " +
1665                   "  UPDATE threads SET snippet_cs = " +
1666                   "   (SELECT snippet_cs FROM" +
1667                   "     (SELECT date * 1000 AS date, sub_cs AS snippet_cs, thread_id FROM pdu" +
1668                   "      UNION SELECT date, 0 AS snippet_cs, thread_id FROM sms)" +
1669                   "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
1670                   "  WHERE threads._id = OLD.thread_id; " +
1671                   "END;");
1672
1673        db.execSQL("CREATE TRIGGER pdu_update_thread_on_delete " +
1674                   "AFTER DELETE ON pdu " +
1675                   "BEGIN " +
1676                   "  UPDATE threads SET " +
1677                   "     date = (strftime('%s','now') * 1000)" +
1678                   "  WHERE threads._id = old.thread_id;" +
1679                   "  UPDATE threads SET message_count = " +
1680                   "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1681                   "      ON threads._id = thread_id" +
1682                   "      WHERE thread_id = old.thread_id" +
1683                   "        AND sms.type != 3) + " +
1684                   "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1685                   "      ON threads._id = thread_id" +
1686                   "      WHERE thread_id = old.thread_id" +
1687                   "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1688                   "        AND msg_box != 3) " +
1689                   "  WHERE threads._id = old.thread_id; " +
1690                   "  UPDATE threads SET snippet = " +
1691                   "   (SELECT snippet FROM" +
1692                   "     (SELECT date * 1000 AS date, sub AS snippet, thread_id FROM pdu" +
1693                   "      UNION SELECT date, body AS snippet, thread_id FROM sms)" +
1694                   "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
1695                   "  WHERE threads._id = OLD.thread_id; " +
1696                   "  UPDATE threads SET snippet_cs = " +
1697                   "   (SELECT snippet_cs FROM" +
1698                   "     (SELECT date * 1000 AS date, sub_cs AS snippet_cs, thread_id FROM pdu" +
1699                   "      UNION SELECT date, 0 AS snippet_cs, thread_id FROM sms)" +
1700                   "    WHERE thread_id = OLD.thread_id ORDER BY date DESC LIMIT 1) " +
1701                   "  WHERE threads._id = OLD.thread_id; " +
1702                   "END;");
1703
1704        db.execSQL("CREATE TABLE temp_part (" +
1705                   "_id INTEGER PRIMARY KEY," +
1706                   "mid INTEGER," +
1707                   "seq INTEGER DEFAULT 0," +
1708                   "ct TEXT," +
1709                   "name TEXT," +
1710                   "chset INTEGER," +
1711                   "cd TEXT," +
1712                   "fn TEXT," +
1713                   "cid TEXT," +
1714                   "cl TEXT," +
1715                   "ctt_s INTEGER," +
1716                   "ctt_t TEXT," +
1717                   "_data TEXT);");
1718        db.execSQL("INSERT INTO temp_part SELECT * FROM part;");
1719        db.execSQL("UPDATE temp_part SET seq='0';");
1720        db.execSQL("UPDATE temp_part SET seq='-1' WHERE ct='application/smil';");
1721        db.execSQL("DROP TABLE IF EXISTS part;");
1722        db.execSQL("ALTER TABLE temp_part RENAME TO part;");
1723    }
1724
1725    private void upgradeDatabaseToVersion38(SQLiteDatabase db) {
1726        db.execSQL("DROP TRIGGER IF EXISTS part_file_cleanup;");
1727        db.execSQL("DROP TRIGGER IF EXISTS drm_file_cleanup;");
1728    }
1729
1730    private void upgradeDatabaseToVersion39(SQLiteDatabase db) {
1731        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_insert");
1732        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_date_subject_on_update");
1733        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
1734        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
1735
1736        db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
1737                "BEGIN" +
1738                "  UPDATE threads SET" +
1739                "    date = (strftime('%s','now') * 1000), " +
1740                "    snippet = new.body," +
1741                "    snippet_cs = 0" +
1742                "  WHERE threads._id = new.thread_id; " +
1743                "  UPDATE threads SET message_count = " +
1744                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1745                "      ON threads._id = thread_id" +
1746                "      WHERE thread_id = new.thread_id" +
1747                "        AND sms.type != 3) + " +
1748                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1749                "      ON threads._id = thread_id" +
1750                "      WHERE thread_id = new.thread_id" +
1751                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1752                "        AND msg_box != 3 " +
1753                "        AND pdu.m_id is NULL) + " +
1754                "     (SELECT COUNT(DISTINCT pdu.m_id) FROM pdu LEFT JOIN threads " +
1755                "      ON threads._id = thread_id" +
1756                "      WHERE thread_id = new.thread_id" +
1757                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1758                "        AND msg_box != 3 " +
1759                "        AND pdu.m_id is not NULL) " +
1760                "  WHERE threads._id = new.thread_id; " +
1761                "  UPDATE threads SET read = " +
1762                "    CASE (SELECT COUNT(*)" +
1763                "          FROM sms" +
1764                "          WHERE read = 0" +
1765                "            AND thread_id = threads._id)" +
1766                "      WHEN 0 THEN 1" +
1767                "      ELSE 0" +
1768                "    END" +
1769                "  WHERE threads._id = new.thread_id; " +
1770                "END;");
1771
1772        db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
1773                "  UPDATE OF date, body, type" +
1774                "  ON sms " +
1775                "BEGIN" +
1776                "  UPDATE threads SET" +
1777                "    date = (strftime('%s','now') * 1000), " +
1778                "    snippet = new.body," +
1779                "    snippet_cs = 0" +
1780                "  WHERE threads._id = new.thread_id; " +
1781                "  UPDATE threads SET message_count = " +
1782                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1783                "      ON threads._id = thread_id" +
1784                "      WHERE thread_id = new.thread_id" +
1785                "        AND sms.type != 3) + " +
1786                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1787                "      ON threads._id = thread_id" +
1788                "      WHERE thread_id = new.thread_id" +
1789                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1790                "        AND msg_box != 3 " +
1791                "        AND pdu.m_id is NULL) + " +
1792                "     (SELECT COUNT(DISTINCT pdu.m_id) FROM pdu LEFT JOIN threads " +
1793                "      ON threads._id = thread_id" +
1794                "      WHERE thread_id = new.thread_id" +
1795                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1796                "        AND msg_box != 3 " +
1797                "        AND pdu.m_id is not NULL) " +
1798                "  WHERE threads._id = new.thread_id; " +
1799                "  UPDATE threads SET read = " +
1800                "    CASE (SELECT COUNT(*)" +
1801                "          FROM sms" +
1802                "          WHERE read = 0" +
1803                "            AND thread_id = threads._id)" +
1804                "      WHEN 0 THEN 1" +
1805                "      ELSE 0" +
1806                "    END" +
1807                "  WHERE threads._id = new.thread_id; " +
1808                "END;");
1809
1810        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON pdu " +
1811                "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1812                "BEGIN" +
1813                "  UPDATE threads SET" +
1814                "    date = (strftime('%s','now') * 1000), " +
1815                "    snippet = new.sub, " +
1816                "    snippet_cs = new.sub_cs" +
1817                "  WHERE threads._id = new.thread_id; " +
1818                "  UPDATE threads SET message_count = " +
1819                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1820                "      ON threads._id = thread_id" +
1821                "      WHERE thread_id = new.thread_id" +
1822                "        AND sms.type != 3) + " +
1823                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1824                "      ON threads._id = thread_id" +
1825                "      WHERE thread_id = new.thread_id" +
1826                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1827                "        AND msg_box != 3 " +
1828                "        AND pdu.m_id is NULL) + " +
1829                "     (SELECT COUNT(DISTINCT pdu.m_id) FROM pdu LEFT JOIN threads " +
1830                "      ON threads._id = thread_id" +
1831                "      WHERE thread_id = new.thread_id" +
1832                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1833                "        AND msg_box != 3 " +
1834                "        AND pdu.m_id is not NULL) " +
1835                "  WHERE threads._id = new.thread_id; " +
1836                "  UPDATE threads SET read = " +
1837                "    CASE (SELECT COUNT(*)" +
1838                "          FROM pdu" +
1839                "          WHERE read = 0 AND thread_id = threads._id)" +
1840                "      WHEN 0 THEN 1 ELSE 0" +
1841                "    END" +
1842                "  WHERE threads._id = new.thread_id; " +
1843                "END;");
1844
1845        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
1846                "  UPDATE OF date, sub, msg_box ON pdu " +
1847                "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1848                "BEGIN" +
1849                "  UPDATE threads SET" +
1850                "    date = (strftime('%s','now') * 1000), " +
1851                "    snippet = new.sub, " +
1852                "    snippet_cs = new.sub_cs" +
1853                "  WHERE threads._id = new.thread_id; " +
1854                "  UPDATE threads SET message_count = " +
1855                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1856                "      ON threads._id = thread_id" +
1857                "      WHERE thread_id = new.thread_id" +
1858                "        AND sms.type != 3) + " +
1859                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1860                "      ON threads._id = thread_id" +
1861                "      WHERE thread_id = new.thread_id" +
1862                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1863                "        AND msg_box != 3 " +
1864                "        AND pdu.m_id is NULL) + " +
1865                "     (SELECT COUNT(DISTINCT pdu.m_id) FROM pdu LEFT JOIN threads " +
1866                "      ON threads._id = thread_id" +
1867                "      WHERE thread_id = new.thread_id" +
1868                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1869                "        AND msg_box != 3 " +
1870                "        AND pdu.m_id is not NULL) " +
1871                "  WHERE threads._id = new.thread_id; " +
1872                "  UPDATE threads SET read = " +
1873                "    CASE (SELECT COUNT(*)" +
1874                "          FROM pdu" +
1875                "          WHERE read = 0 AND thread_id = threads._id)" +
1876                "      WHEN 0 THEN 1 ELSE 0" +
1877                "    END" +
1878                "  WHERE threads._id = new.thread_id; " +
1879                "END;");
1880    }
1881
1882    private void upgradeDatabaseToVersion40(SQLiteDatabase db) {
1883        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_insert");
1884        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_date_subject_on_update");
1885        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
1886        db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
1887
1888        db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
1889                "BEGIN" +
1890                "  UPDATE threads SET" +
1891                "    date = (strftime('%s','now') * 1000), " +
1892                "    snippet = new.body," +
1893                "    snippet_cs = 0" +
1894                "  WHERE threads._id = new.thread_id; " +
1895                "  UPDATE threads SET message_count = " +
1896                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1897                "      ON threads._id = thread_id" +
1898                "      WHERE thread_id = new.thread_id" +
1899                "        AND sms.type != 3) + " +
1900                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1901                "      ON threads._id = thread_id" +
1902                "      WHERE thread_id = new.thread_id" +
1903                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1904                "        AND msg_box != 3) " +
1905                "  WHERE threads._id = new.thread_id; " +
1906                "  UPDATE threads SET read = " +
1907                "    CASE (SELECT COUNT(*)" +
1908                "          FROM sms" +
1909                "          WHERE read = 0" +
1910                "            AND thread_id = threads._id)" +
1911                "      WHEN 0 THEN 1" +
1912                "      ELSE 0" +
1913                "    END" +
1914                "  WHERE threads._id = new.thread_id; " +
1915                "END;");
1916
1917        db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
1918                "  UPDATE OF date, body, type" +
1919                "  ON sms " +
1920                "BEGIN" +
1921                "  UPDATE threads SET" +
1922                "    date = (strftime('%s','now') * 1000), " +
1923                "    snippet = new.body," +
1924                "    snippet_cs = 0" +
1925                "  WHERE threads._id = new.thread_id; " +
1926                "  UPDATE threads SET message_count = " +
1927                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1928                "      ON threads._id = thread_id" +
1929                "      WHERE thread_id = new.thread_id" +
1930                "        AND sms.type != 3) + " +
1931                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1932                "      ON threads._id = thread_id" +
1933                "      WHERE thread_id = new.thread_id" +
1934                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1935                "        AND msg_box != 3) " +
1936                "  WHERE threads._id = new.thread_id; " +
1937                "  UPDATE threads SET read = " +
1938                "    CASE (SELECT COUNT(*)" +
1939                "          FROM sms" +
1940                "          WHERE read = 0" +
1941                "            AND thread_id = threads._id)" +
1942                "      WHEN 0 THEN 1" +
1943                "      ELSE 0" +
1944                "    END" +
1945                "  WHERE threads._id = new.thread_id; " +
1946                "END;");
1947
1948        db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON pdu " +
1949                "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1950                "BEGIN" +
1951                "  UPDATE threads SET" +
1952                "    date = (strftime('%s','now') * 1000), " +
1953                "    snippet = new.sub, " +
1954                "    snippet_cs = new.sub_cs" +
1955                "  WHERE threads._id = new.thread_id; " +
1956                "  UPDATE threads SET message_count = " +
1957                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1958                "      ON threads._id = thread_id" +
1959                "      WHERE thread_id = new.thread_id" +
1960                "        AND sms.type != 3) + " +
1961                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1962                "      ON threads._id = thread_id" +
1963                "      WHERE thread_id = new.thread_id" +
1964                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1965                "        AND msg_box != 3) " +
1966                "  WHERE threads._id = new.thread_id; " +
1967                "  UPDATE threads SET read = " +
1968                "    CASE (SELECT COUNT(*)" +
1969                "          FROM pdu" +
1970                "          WHERE read = 0 AND thread_id = threads._id)" +
1971                "      WHEN 0 THEN 1 ELSE 0" +
1972                "    END" +
1973                "  WHERE threads._id = new.thread_id; " +
1974                "END;");
1975
1976        db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
1977                "  UPDATE OF date, sub, msg_box ON pdu " +
1978                "  WHEN new.m_type=132 OR new.m_type=130 OR new.m_type=128 " +
1979                "BEGIN" +
1980                "  UPDATE threads SET" +
1981                "    date = (strftime('%s','now') * 1000), " +
1982                "    snippet = new.sub, " +
1983                "    snippet_cs = new.sub_cs" +
1984                "  WHERE threads._id = new.thread_id; " +
1985                "  UPDATE threads SET message_count = " +
1986                "     (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
1987                "      ON threads._id = thread_id" +
1988                "      WHERE thread_id = new.thread_id" +
1989                "        AND sms.type != 3) + " +
1990                "     (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
1991                "      ON threads._id = thread_id" +
1992                "      WHERE thread_id = new.thread_id" +
1993                "        AND (m_type=132 OR m_type=130 OR m_type=128)" +
1994                "        AND msg_box != 3) " +
1995                "  WHERE threads._id = new.thread_id; " +
1996                "  UPDATE threads SET read = " +
1997                "    CASE (SELECT COUNT(*)" +
1998                "          FROM pdu" +
1999                "          WHERE read = 0 AND thread_id = threads._id)" +
2000                "      WHEN 0 THEN 1 ELSE 0" +
2001                "    END" +
2002                "  WHERE threads._id = new.thread_id; " +
2003                "END;");
2004    }
2005
2006    private void upgradeDatabaseToVersion41(SQLiteDatabase db) {
2007        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_move_mms");
2008        db.execSQL("CREATE TRIGGER update_threads_error_on_move_mms " +
2009                   "  BEFORE UPDATE OF msg_box ON pdu " +
2010                   "  WHEN (OLD.msg_box = 4 AND NEW.msg_box != 4) " +
2011                   "  AND (OLD._id IN (SELECT DISTINCT msg_id" +
2012                   "                   FROM pending_msgs" +
2013                   "                   WHERE err_type >= 10)) " +
2014                   "BEGIN " +
2015                   "  UPDATE threads SET error = error - 1" +
2016                   "  WHERE _id = OLD.thread_id; " +
2017                   "END;");
2018    }
2019
2020    private void upgradeDatabaseToVersion42(SQLiteDatabase db) {
2021        db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
2022        db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_sms");
2023        db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete_sms");
2024    }
2025}
2026