blob: cf4d07ffcb4ec56734eea6da94e356b369ff3158 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 android.database.sqlite;
18
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -070019import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.ContentValues;
21import android.database.Cursor;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070022import android.database.DatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.database.DatabaseUtils;
Vasu Nori062fc7ce2010-03-31 16:13:05 -070024import android.database.DefaultDatabaseErrorHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.database.SQLException;
Vasu Noric3849202010-03-09 10:47:25 -080026import android.database.sqlite.SQLiteDebug.DbStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.os.Debug;
Vasu Noria8c24902010-06-01 11:30:27 -070028import android.os.StatFs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.SystemClock;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070030import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.text.TextUtils;
32import android.util.Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.EventLog;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070034import android.util.Log;
Vasu Noric3849202010-03-09 10:47:25 -080035import android.util.Pair;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -070037import dalvik.system.BlockGuard;
38
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import java.io.File;
Vasu Noric3849202010-03-09 10:47:25 -080040import java.lang.ref.WeakReference;
Vasu Noric3849202010-03-09 10:47:25 -080041import java.util.ArrayList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.util.HashMap;
Vasu Noric3849202010-03-09 10:47:25 -080043import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import java.util.Iterator;
Vasu Nori20f549f2010-04-15 11:25:51 -070045import java.util.LinkedHashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import java.util.Locale;
47import java.util.Map;
Dan Egnor12311952009-11-23 14:47:45 -080048import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.util.Set;
50import java.util.WeakHashMap;
51import java.util.concurrent.locks.ReentrantLock;
Brad Fitzpatrickd8330232010-02-19 10:59:01 -080052import java.util.regex.Pattern;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54/**
55 * Exposes methods to manage a SQLite database.
56 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
57 * perform other common database management tasks.
58 * <p>See the Notepad sample application in the SDK for an example of creating
59 * and managing a database.
60 * <p> Database names must be unique within an application, not across all
61 * applications.
62 *
63 * <h3>Localized Collation - ORDER BY</h3>
64 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
65 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
66 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
67 * is the Unicode Collation Algorithm and not tailored to the current locale.
68 */
69public class SQLiteDatabase extends SQLiteClosable {
70 private static final String TAG = "Database";
Jeff Hamilton082c2af2009-09-29 11:49:51 -070071 private static final int EVENT_DB_OPERATION = 52000;
72 private static final int EVENT_DB_CORRUPT = 75004;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073
74 /**
75 * Algorithms used in ON CONFLICT clause
76 * http://www.sqlite.org/lang_conflict.html
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 */
Vasu Nori8d45e4e2010-02-05 22:35:47 -080078 /**
79 * When a constraint violation occurs, an immediate ROLLBACK occurs,
80 * thus ending the current transaction, and the command aborts with a
81 * return code of SQLITE_CONSTRAINT. If no transaction is active
82 * (other than the implied transaction that is created on every command)
83 * then this algorithm works the same as ABORT.
84 */
85 public static final int CONFLICT_ROLLBACK = 1;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070086
Vasu Nori8d45e4e2010-02-05 22:35:47 -080087 /**
88 * When a constraint violation occurs,no ROLLBACK is executed
89 * so changes from prior commands within the same transaction
90 * are preserved. This is the default behavior.
91 */
92 public static final int CONFLICT_ABORT = 2;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070093
Vasu Nori8d45e4e2010-02-05 22:35:47 -080094 /**
95 * When a constraint violation occurs, the command aborts with a return
96 * code SQLITE_CONSTRAINT. But any changes to the database that
97 * the command made prior to encountering the constraint violation
98 * are preserved and are not backed out.
99 */
100 public static final int CONFLICT_FAIL = 3;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700101
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800102 /**
103 * When a constraint violation occurs, the one row that contains
104 * the constraint violation is not inserted or changed.
105 * But the command continues executing normally. Other rows before and
106 * after the row that contained the constraint violation continue to be
107 * inserted or updated normally. No error is returned.
108 */
109 public static final int CONFLICT_IGNORE = 4;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700110
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800111 /**
112 * When a UNIQUE constraint violation occurs, the pre-existing rows that
113 * are causing the constraint violation are removed prior to inserting
114 * or updating the current row. Thus the insert or update always occurs.
115 * The command continues executing normally. No error is returned.
116 * If a NOT NULL constraint violation occurs, the NULL value is replaced
117 * by the default value for that column. If the column has no default
118 * value, then the ABORT algorithm is used. If a CHECK constraint
119 * violation occurs then the IGNORE algorithm is used. When this conflict
120 * resolution strategy deletes rows in order to satisfy a constraint,
121 * it does not invoke delete triggers on those rows.
122 * This behavior might change in a future release.
123 */
124 public static final int CONFLICT_REPLACE = 5;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700125
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800126 /**
127 * use the following when no conflict action is specified.
128 */
129 public static final int CONFLICT_NONE = 0;
130 private static final String[] CONFLICT_VALUES = new String[]
131 {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 /**
134 * Maximum Length Of A LIKE Or GLOB Pattern
135 * The pattern matching algorithm used in the default LIKE and GLOB implementation
136 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
137 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
138 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
139 * The default value of this limit is 50000. A modern workstation can evaluate
140 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
141 * The denial of service problem only comes into play when the pattern length gets
142 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
143 * are at most a few dozen bytes in length, paranoid application developers may
144 * want to reduce this parameter to something in the range of a few hundred
145 * if they know that external users are able to generate arbitrary patterns.
146 */
147 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
148
149 /**
150 * Flag for {@link #openDatabase} to open the database for reading and writing.
151 * If the disk is full, this may fail even before you actually write anything.
152 *
153 * {@more} Note that the value of this flag is 0, so it is the default.
154 */
155 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
156
157 /**
158 * Flag for {@link #openDatabase} to open the database for reading only.
159 * This is the only reliable way to open a database if the disk may be full.
160 */
161 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
162
163 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
164
165 /**
166 * Flag for {@link #openDatabase} to open the database without support for localized collators.
167 *
168 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
169 * You must be consistent when using this flag to use the setting the database was
170 * created with. If this is set, {@link #setLocale} will do nothing.
171 */
172 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
173
174 /**
175 * Flag for {@link #openDatabase} to create the database file if it does not already exist.
176 */
177 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
178
179 /**
180 * Indicates whether the most-recently started transaction has been marked as successful.
181 */
182 private boolean mInnerTransactionIsSuccessful;
183
184 /**
185 * Valid during the life of a transaction, and indicates whether the entire transaction (the
186 * outer one and all of the inner ones) so far has been successful.
187 */
188 private boolean mTransactionIsSuccessful;
189
Fred Quintanac4516a72009-09-03 12:14:06 -0700190 /**
191 * Valid during the life of a transaction.
192 */
193 private SQLiteTransactionListener mTransactionListener;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 /** Synchronize on this when accessing the database */
196 private final ReentrantLock mLock = new ReentrantLock(true);
197
198 private long mLockAcquiredWallTime = 0L;
199 private long mLockAcquiredThreadTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 // limit the frequency of complaints about each database to one within 20 sec
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700202 // unless run command adb shell setprop log.tag.Database VERBOSE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
204 /** If the lock is held this long then a warning will be printed when it is released. */
205 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
206 private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
207 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
208
Dmitri Plotnikovb43b58d2009-09-09 18:10:42 -0700209 private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700210
Brad Fitzpatrickd8330232010-02-19 10:59:01 -0800211 // The pattern we remove from database filenames before
212 // potentially logging them.
213 private static final Pattern EMAIL_IN_DB_PATTERN = Pattern.compile("[\\w\\.\\-]+@[\\w\\.\\-]+");
214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 private long mLastLockMessageTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700216
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800217 // Things related to query logging/sampling for debugging
218 // slow/frequent queries during development. Always log queries
Brad Fitzpatrick722802e2010-03-23 22:22:16 -0700219 // which take (by default) 500ms+; shorter queries are sampled
220 // accordingly. Commit statements, which are typically slow, are
221 // logged together with the most recently executed SQL statement,
222 // for disambiguation. The 500ms value is configurable via a
223 // SystemProperty, but developers actively debugging database I/O
224 // should probably use the regular log tunable,
225 // LOG_SLOW_QUERIES_PROPERTY, defined below.
226 private static int sQueryLogTimeInMillis = 0; // lazily initialized
Dan Egnor12311952009-11-23 14:47:45 -0800227 private static final int QUERY_LOG_SQL_LENGTH = 64;
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800228 private static final String COMMIT_SQL = "COMMIT;";
Dan Egnor12311952009-11-23 14:47:45 -0800229 private final Random mRandom = new Random();
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800230 private String mLastSqlStatement = null;
Dan Egnor12311952009-11-23 14:47:45 -0800231
Brad Fitzpatrick722802e2010-03-23 22:22:16 -0700232 // String prefix for slow database query EventLog records that show
233 // lock acquistions of the database.
234 /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:";
235
Vasu Nori6f37f832010-05-19 11:53:25 -0700236 /** Used by native code, do not rename. make it volatile, so it is thread-safe. */
237 /* package */ volatile int mNativeHandle = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 /** Used to make temp table names unique */
240 /* package */ int mTempTableSequence = 0;
241
Vasu Noria8c24902010-06-01 11:30:27 -0700242 /**
243 * The size, in bytes, of a block on "/data". This corresponds to the Unix
244 * statfs.f_bsize field. note that this field is lazily initialized.
245 */
246 private static int sBlockSize = 0;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 /** The path for the database file */
Vasu Noriccd95442010-05-28 17:04:16 -0700249 private final String mPath;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
Brad Fitzpatrickd8330232010-02-19 10:59:01 -0800251 /** The anonymized path for the database file for logging purposes */
252 private String mPathForLogs = null; // lazily populated
253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 /** The flags passed to open/create */
Vasu Noriccd95442010-05-28 17:04:16 -0700255 private final int mFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 /** The optional factory to use when creating new Cursors */
Vasu Noriccd95442010-05-28 17:04:16 -0700258 private final CursorFactory mFactory;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700259
Vasu Nori21343692010-06-03 16:01:39 -0700260 private final WeakHashMap<SQLiteClosable, Object> mPrograms;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700261
Vasu Nori5a03f362009-10-20 15:16:35 -0700262 /**
Vasu Nori20f549f2010-04-15 11:25:51 -0700263 * for each instance of this class, a LRU cache is maintained to store
Vasu Nori5a03f362009-10-20 15:16:35 -0700264 * the compiled query statement ids returned by sqlite database.
Vasu Noriccd95442010-05-28 17:04:16 -0700265 * key = SQL statement with "?" for bind args
Vasu Nori5a03f362009-10-20 15:16:35 -0700266 * value = {@link SQLiteCompiledSql}
267 * If an application opens the database and keeps it open during its entire life, then
Vasu Noriccd95442010-05-28 17:04:16 -0700268 * there will not be an overhead of compilation of SQL statements by sqlite.
Vasu Nori5a03f362009-10-20 15:16:35 -0700269 *
270 * why is this cache NOT static? because sqlite attaches compiledsql statements to the
271 * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
272 * invoked.
273 *
274 * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
Vasu Nori9504c702010-04-23 01:04:31 -0700275 * (@link setMaxSqlCacheSize(int)}).
Vasu Nori5a03f362009-10-20 15:16:35 -0700276 */
Vasu Nori20f549f2010-04-15 11:25:51 -0700277 // default statement-cache size per database connection ( = instance of this class)
278 private int mMaxSqlCacheSize = 25;
Vasu Nori21343692010-06-03 16:01:39 -0700279 /* package */ final Map<String, SQLiteCompiledSql> mCompiledQueries =
Vasu Nori20f549f2010-04-15 11:25:51 -0700280 new LinkedHashMap<String, SQLiteCompiledSql>(mMaxSqlCacheSize + 1, 0.75f, true) {
281 @Override
282 public boolean removeEldestEntry(Map.Entry<String, SQLiteCompiledSql> eldest) {
Vasu Nori9504c702010-04-23 01:04:31 -0700283 // eldest = least-recently used entry
284 // if it needs to be removed to accommodate a new entry,
285 // close {@link SQLiteCompiledSql} represented by this entry, if not in use
286 // and then let it be removed from the Map.
Vasu Nori9463f292010-04-30 12:22:18 -0700287 // when this is called, the caller must be trying to add a just-compiled stmt
288 // to cache; i.e., caller should already have acquired database lock AND
289 // the lock on mCompiledQueries. do as assert of these two 2 facts.
290 verifyLockOwner();
291 if (this.size() <= mMaxSqlCacheSize) {
292 // cache is not full. nothing needs to be removed
293 return false;
Vasu Nori9504c702010-04-23 01:04:31 -0700294 }
Vasu Nori9463f292010-04-30 12:22:18 -0700295 // cache is full. eldest will be removed.
296 SQLiteCompiledSql entry = eldest.getValue();
297 if (!entry.isInUse()) {
298 // this {@link SQLiteCompiledSql} is not in use. release it.
299 entry.releaseSqlStatement();
300 }
301 // return true, so that this entry is removed automatically by the caller.
302 return true;
Vasu Nori20f549f2010-04-15 11:25:51 -0700303 }
304 };
Vasu Norie495d1f2010-01-06 16:34:19 -0800305 /**
Vasu Nori20f549f2010-04-15 11:25:51 -0700306 * absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}
Vasu Nori90a367262010-04-12 12:49:09 -0700307 * size of each prepared-statement is between 1K - 6K, depending on the complexity of the
Vasu Noriccd95442010-05-28 17:04:16 -0700308 * SQL statement & schema.
Vasu Norie495d1f2010-01-06 16:34:19 -0800309 */
Vasu Nori90a367262010-04-12 12:49:09 -0700310 public static final int MAX_SQL_CACHE_SIZE = 100;
Vasu Norie9d92102010-01-20 15:07:26 -0800311 private int mCacheFullWarnings;
Vasu Nori49d02ac2010-03-05 21:49:30 -0800312 private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 1;
Vasu Nori5a03f362009-10-20 15:16:35 -0700313
314 /** maintain stats about number of cache hits and misses */
315 private int mNumCacheHits;
316 private int mNumCacheMisses;
317
Vasu Norid606b4b2010-02-24 12:54:20 -0800318 /** Used to find out where this object was created in case it never got closed. */
Vasu Nori21343692010-06-03 16:01:39 -0700319 private final Throwable mStackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320
Dmitri Plotnikov90142c92009-09-15 10:52:17 -0700321 // System property that enables logging of slow queries. Specify the threshold in ms.
322 private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
323 private final int mSlowQueryThreshold;
324
Vasu Nori6f37f832010-05-19 11:53:25 -0700325 /** stores the list of statement ids that need to be finalized by sqlite */
Vasu Nori21343692010-06-03 16:01:39 -0700326 private final ArrayList<Integer> mClosedStatementIds = new ArrayList<Integer>();
Vasu Nori6f37f832010-05-19 11:53:25 -0700327
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700328 /** {@link DatabaseErrorHandler} to be used when SQLite returns any of the following errors
329 * Corruption
330 * */
Vasu Nori21343692010-06-03 16:01:39 -0700331 private final DatabaseErrorHandler mErrorHandler;
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700332
Vasu Nori6c354da2010-04-26 23:33:39 -0700333 /** The Database connection pool {@link DatabaseConnectionPool}.
334 * Visibility is package-private for testing purposes. otherwise, private visibility is enough.
335 */
336 /* package */ volatile DatabaseConnectionPool mConnectionPool = null;
337
338 /** Each database connection handle in the pool is assigned a number 1..N, where N is the
339 * size of the connection pool.
340 * The main connection handle to which the pool is attached is assigned a value of 0.
341 */
342 /* package */ final short mConnectionNum;
343
Vasu Nori65a88832010-07-16 15:14:08 -0700344 /** on pooled database connections, this member points to the parent ( = main)
345 * database connection handle.
346 * package visibility only for testing purposes
347 */
348 /* package */ SQLiteDatabase mParentConnObj = null;
349
Vasu Noria98cb262010-06-22 13:16:35 -0700350 private static final String MEMORY_DB_PATH = ":memory:";
351
Vasu Nori2827d6d2010-07-04 00:26:18 -0700352 synchronized void addSQLiteClosable(SQLiteClosable closable) {
353 // mPrograms is per instance of SQLiteDatabase and it doesn't actually touch the database
354 // itself. so, there is no need to lock().
355 mPrograms.put(closable, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700357
Vasu Nori2827d6d2010-07-04 00:26:18 -0700358 synchronized void removeSQLiteClosable(SQLiteClosable closable) {
359 mPrograms.remove(closable);
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700360 }
361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 @Override
363 protected void onAllReferencesReleased() {
364 if (isOpen()) {
Vasu Noriad239ab2010-06-14 16:58:47 -0700365 // close the database which will close all pending statements to be finalized also
366 close();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368 }
369
370 /**
371 * Attempts to release memory that SQLite holds but does not require to
372 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700373 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 * @return the number of bytes actually released
375 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700376 static public native int releaseMemory();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377
378 /**
379 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
380 * around critical sections. This is pretty expensive, so if you know that your
381 * DB will only be used by a single thread then you should set this to false.
382 * The default is true.
383 * @param lockingEnabled set to true to enable locks, false otherwise
384 */
385 public void setLockingEnabled(boolean lockingEnabled) {
386 mLockingEnabled = lockingEnabled;
387 }
388
389 /**
390 * If set then the SQLiteDatabase is made thread-safe by using locks
391 * around critical sections
392 */
393 private boolean mLockingEnabled = true;
394
395 /* package */ void onCorruption() {
Vasu Norif3cf8a42010-03-23 11:41:44 -0700396 EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
Vasu Noriccd95442010-05-28 17:04:16 -0700397 mErrorHandler.onCorruption(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 }
399
400 /**
401 * Locks the database for exclusive access. The database lock must be held when
402 * touch the native sqlite3* object since it is single threaded and uses
403 * a polling lock contention algorithm. The lock is recursive, and may be acquired
404 * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700405 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 * @see #unlock()
407 */
408 /* package */ void lock() {
Vasu Nori7b04c412010-07-20 10:31:21 -0700409 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 if (!mLockingEnabled) return;
411 mLock.lock();
412 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
413 if (mLock.getHoldCount() == 1) {
414 // Use elapsed real-time since the CPU may sleep when waiting for IO
415 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
416 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
417 }
418 }
419 }
420
421 /**
422 * Locks the database for exclusive access. The database lock must be held when
423 * touch the native sqlite3* object since it is single threaded and uses
424 * a polling lock contention algorithm. The lock is recursive, and may be acquired
425 * multiple times by the same thread.
426 *
427 * @see #unlockForced()
428 */
429 private void lockForced() {
Vasu Nori7b04c412010-07-20 10:31:21 -0700430 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 mLock.lock();
432 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
433 if (mLock.getHoldCount() == 1) {
434 // Use elapsed real-time since the CPU may sleep when waiting for IO
435 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
436 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
437 }
438 }
439 }
440
441 /**
442 * Releases the database lock. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700443 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 * @see #unlock()
445 */
446 /* package */ void unlock() {
447 if (!mLockingEnabled) return;
448 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
449 if (mLock.getHoldCount() == 1) {
450 checkLockHoldTime();
451 }
452 }
453 mLock.unlock();
454 }
455
456 /**
457 * Releases the database lock.
458 *
459 * @see #unlockForced()
460 */
461 private void unlockForced() {
462 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
463 if (mLock.getHoldCount() == 1) {
464 checkLockHoldTime();
465 }
466 }
467 mLock.unlock();
468 }
469
470 private void checkLockHoldTime() {
471 // Use elapsed real-time since the CPU may sleep when waiting for IO
472 long elapsedTime = SystemClock.elapsedRealtime();
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700473 long lockedTime = elapsedTime - mLockAcquiredWallTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
475 !Log.isLoggable(TAG, Log.VERBOSE) &&
476 (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
477 return;
478 }
479 if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
480 int threadTime = (int)
481 ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
482 if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
483 lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
484 mLastLockMessageTime = elapsedTime;
485 String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
486 + threadTime + "ms";
487 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
488 Log.d(TAG, msg, new Exception());
489 } else {
490 Log.d(TAG, msg);
491 }
492 }
493 }
494 }
495
496 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700497 * Begins a transaction in EXCLUSIVE mode.
498 * <p>
499 * Transactions can be nested.
500 * When the outer transaction is ended all of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 * the work done in that transaction and all of the nested transactions will be committed or
502 * rolled back. The changes will be rolled back if any transaction is ended without being
503 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700504 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 * <p>Here is the standard idiom for transactions:
506 *
507 * <pre>
508 * db.beginTransaction();
509 * try {
510 * ...
511 * db.setTransactionSuccessful();
512 * } finally {
513 * db.endTransaction();
514 * }
515 * </pre>
516 */
517 public void beginTransaction() {
Vasu Nori6c354da2010-04-26 23:33:39 -0700518 beginTransaction(null /* transactionStatusCallback */, true);
519 }
520
521 /**
522 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
523 * the outer transaction is ended all of the work done in that transaction
524 * and all of the nested transactions will be committed or rolled back. The
525 * changes will be rolled back if any transaction is ended without being
526 * marked as clean (by calling setTransactionSuccessful). Otherwise they
527 * will be committed.
528 * <p>
529 * Here is the standard idiom for transactions:
530 *
531 * <pre>
532 * db.beginTransactionNonExclusive();
533 * try {
534 * ...
535 * db.setTransactionSuccessful();
536 * } finally {
537 * db.endTransaction();
538 * }
539 * </pre>
540 */
541 public void beginTransactionNonExclusive() {
542 beginTransaction(null /* transactionStatusCallback */, false);
Fred Quintanac4516a72009-09-03 12:14:06 -0700543 }
544
545 /**
Vasu Noriccd95442010-05-28 17:04:16 -0700546 * Begins a transaction in EXCLUSIVE mode.
547 * <p>
548 * Transactions can be nested.
549 * When the outer transaction is ended all of
Fred Quintanac4516a72009-09-03 12:14:06 -0700550 * the work done in that transaction and all of the nested transactions will be committed or
551 * rolled back. The changes will be rolled back if any transaction is ended without being
552 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
Vasu Noriccd95442010-05-28 17:04:16 -0700553 * </p>
Fred Quintanac4516a72009-09-03 12:14:06 -0700554 * <p>Here is the standard idiom for transactions:
555 *
556 * <pre>
557 * db.beginTransactionWithListener(listener);
558 * try {
559 * ...
560 * db.setTransactionSuccessful();
561 * } finally {
562 * db.endTransaction();
563 * }
564 * </pre>
Vasu Noriccd95442010-05-28 17:04:16 -0700565 *
Fred Quintanac4516a72009-09-03 12:14:06 -0700566 * @param transactionListener listener that should be notified when the transaction begins,
567 * commits, or is rolled back, either explicitly or by a call to
568 * {@link #yieldIfContendedSafely}.
569 */
570 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700571 beginTransaction(transactionListener, true);
572 }
573
574 /**
575 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
576 * the outer transaction is ended all of the work done in that transaction
577 * and all of the nested transactions will be committed or rolled back. The
578 * changes will be rolled back if any transaction is ended without being
579 * marked as clean (by calling setTransactionSuccessful). Otherwise they
580 * will be committed.
581 * <p>
582 * Here is the standard idiom for transactions:
583 *
584 * <pre>
585 * db.beginTransactionWithListenerNonExclusive(listener);
586 * try {
587 * ...
588 * db.setTransactionSuccessful();
589 * } finally {
590 * db.endTransaction();
591 * }
592 * </pre>
593 *
594 * @param transactionListener listener that should be notified when the
595 * transaction begins, commits, or is rolled back, either
596 * explicitly or by a call to {@link #yieldIfContendedSafely}.
597 */
598 public void beginTransactionWithListenerNonExclusive(
599 SQLiteTransactionListener transactionListener) {
600 beginTransaction(transactionListener, false);
601 }
602
603 private void beginTransaction(SQLiteTransactionListener transactionListener,
604 boolean exclusive) {
Vasu Noriccd95442010-05-28 17:04:16 -0700605 verifyDbIsOpen();
Vasu Noric8e1f232010-04-13 15:05:09 -0700606 lockForced();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 boolean ok = false;
608 try {
609 // If this thread already had the lock then get out
610 if (mLock.getHoldCount() > 1) {
611 if (mInnerTransactionIsSuccessful) {
612 String msg = "Cannot call beginTransaction between "
613 + "calling setTransactionSuccessful and endTransaction";
614 IllegalStateException e = new IllegalStateException(msg);
615 Log.e(TAG, "beginTransaction() failed", e);
616 throw e;
617 }
618 ok = true;
619 return;
620 }
621
622 // This thread didn't already have the lock, so begin a database
623 // transaction now.
Vasu Nori57feb5d2010-06-22 10:39:04 -0700624 // STOPSHIP - uncomment the following 1 line
625 // if (exclusive) {
626 // STOPSHIP - remove the following 1 line
627 if (exclusive && mConnectionPool == null) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700628 execSQL("BEGIN EXCLUSIVE;");
629 } else {
630 execSQL("BEGIN IMMEDIATE;");
631 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700632 mTransactionListener = transactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 mTransactionIsSuccessful = true;
634 mInnerTransactionIsSuccessful = false;
Fred Quintanac4516a72009-09-03 12:14:06 -0700635 if (transactionListener != null) {
636 try {
637 transactionListener.onBegin();
638 } catch (RuntimeException e) {
639 execSQL("ROLLBACK;");
640 throw e;
641 }
642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 ok = true;
644 } finally {
645 if (!ok) {
646 // beginTransaction is called before the try block so we must release the lock in
647 // the case of failure.
648 unlockForced();
649 }
650 }
651 }
652
653 /**
654 * End a transaction. See beginTransaction for notes about how to use this and when transactions
655 * are committed and rolled back.
656 */
657 public void endTransaction() {
Vasu Noriccd95442010-05-28 17:04:16 -0700658 verifyLockOwner();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 try {
660 if (mInnerTransactionIsSuccessful) {
661 mInnerTransactionIsSuccessful = false;
662 } else {
663 mTransactionIsSuccessful = false;
664 }
665 if (mLock.getHoldCount() != 1) {
666 return;
667 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700668 RuntimeException savedException = null;
669 if (mTransactionListener != null) {
670 try {
671 if (mTransactionIsSuccessful) {
672 mTransactionListener.onCommit();
673 } else {
674 mTransactionListener.onRollback();
675 }
676 } catch (RuntimeException e) {
677 savedException = e;
678 mTransactionIsSuccessful = false;
679 }
680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 if (mTransactionIsSuccessful) {
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -0800682 execSQL(COMMIT_SQL);
Vasu Nori6c354da2010-04-26 23:33:39 -0700683 // if write-ahead logging is used, we have to take care of checkpoint.
684 // TODO: should applications be given the flexibility of choosing when to
685 // trigger checkpoint?
686 // for now, do checkpoint after every COMMIT because that is the fastest
687 // way to guarantee that readers will see latest data.
688 // but this is the slowest way to run sqlite with in write-ahead logging mode.
689 if (this.mConnectionPool != null) {
690 execSQL("PRAGMA wal_checkpoint;");
691 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
692 Log.i(TAG, "PRAGMA wal_Checkpoint done");
693 }
694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 } else {
696 try {
697 execSQL("ROLLBACK;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700698 if (savedException != null) {
699 throw savedException;
700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 } catch (SQLException e) {
702 if (Config.LOGD) {
703 Log.d(TAG, "exception during rollback, maybe the DB previously "
704 + "performed an auto-rollback");
705 }
706 }
707 }
708 } finally {
Fred Quintanac4516a72009-09-03 12:14:06 -0700709 mTransactionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 unlockForced();
711 if (Config.LOGV) {
712 Log.v(TAG, "unlocked " + Thread.currentThread()
713 + ", holdCount is " + mLock.getHoldCount());
714 }
715 }
716 }
717
718 /**
719 * Marks the current transaction as successful. Do not do any more database work between
720 * calling this and calling endTransaction. Do as little non-database work as possible in that
721 * situation too. If any errors are encountered between this and endTransaction the transaction
722 * will still be committed.
723 *
724 * @throws IllegalStateException if the current thread is not in a transaction or the
725 * transaction is already marked as successful.
726 */
727 public void setTransactionSuccessful() {
Vasu Noriccd95442010-05-28 17:04:16 -0700728 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 if (!mLock.isHeldByCurrentThread()) {
730 throw new IllegalStateException("no transaction pending");
731 }
732 if (mInnerTransactionIsSuccessful) {
733 throw new IllegalStateException(
734 "setTransactionSuccessful may only be called once per call to beginTransaction");
735 }
736 mInnerTransactionIsSuccessful = true;
737 }
738
739 /**
740 * return true if there is a transaction pending
741 */
742 public boolean inTransaction() {
743 return mLock.getHoldCount() > 0;
744 }
745
746 /**
747 * Checks if the database lock is held by this thread.
748 *
749 * @return true, if this thread is holding the database lock.
750 */
751 public boolean isDbLockedByCurrentThread() {
752 return mLock.isHeldByCurrentThread();
753 }
754
755 /**
756 * Checks if the database is locked by another thread. This is
757 * just an estimate, since this status can change at any time,
758 * including after the call is made but before the result has
759 * been acted upon.
760 *
761 * @return true, if the database is locked by another thread
762 */
763 public boolean isDbLockedByOtherThreads() {
764 return !mLock.isHeldByCurrentThread() && mLock.isLocked();
765 }
766
767 /**
768 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
769 * successful so far. Do not call setTransactionSuccessful before calling this. When this
770 * returns a new transaction will have been created but not marked as successful.
771 * @return true if the transaction was yielded
772 * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
773 * will not be yielded. Use yieldIfContendedSafely instead.
774 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700775 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700777 return yieldIfContendedHelper(false /* do not check yielding */,
778 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 }
780
781 /**
782 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
783 * successful so far. Do not call setTransactionSuccessful before calling this. When this
784 * returns a new transaction will have been created but not marked as successful. This assumes
785 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700786 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 * @return true if the transaction was yielded
788 */
789 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700790 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 }
792
Fred Quintana5c7aede2009-08-27 21:41:27 -0700793 /**
794 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
795 * successful so far. Do not call setTransactionSuccessful before calling this. When this
796 * returns a new transaction will have been created but not marked as successful. This assumes
797 * that there are no nested transactions (beginTransaction has only been called once) and will
798 * throw an exception if that is not the case.
799 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
800 * the lock was actually yielded. This will allow other background threads to make some
801 * more progress than they would if we started the transaction immediately.
802 * @return true if the transaction was yielded
803 */
804 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
805 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
806 }
807
808 private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 if (mLock.getQueueLength() == 0) {
810 // Reset the lock acquire time since we know that the thread was willing to yield
811 // the lock at this time.
812 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
813 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
814 return false;
815 }
816 setTransactionSuccessful();
Fred Quintanac4516a72009-09-03 12:14:06 -0700817 SQLiteTransactionListener transactionListener = mTransactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 endTransaction();
819 if (checkFullyYielded) {
820 if (this.isDbLockedByCurrentThread()) {
821 throw new IllegalStateException(
822 "Db locked more than once. yielfIfContended cannot yield");
823 }
824 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700825 if (sleepAfterYieldDelay > 0) {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700826 // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
827 // check if anyone is using the database. If the database is not contended,
828 // retake the lock and return.
829 long remainingDelay = sleepAfterYieldDelay;
830 while (remainingDelay > 0) {
831 try {
832 Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
833 remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
834 } catch (InterruptedException e) {
835 Thread.interrupted();
836 }
837 remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
838 if (mLock.getQueueLength() == 0) {
839 break;
840 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700841 }
842 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700843 beginTransactionWithListener(transactionListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 return true;
845 }
846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 /**
Vasu Nori95675132010-07-21 16:24:40 -0700848 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 */
Vasu Nori95675132010-07-21 16:24:40 -0700850 @Deprecated
851 public Map<String, String> getSyncedTables() {
852 return new HashMap<String, String>(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
855 /**
856 * Used to allow returning sub-classes of {@link Cursor} when calling query.
857 */
858 public interface CursorFactory {
859 /**
860 * See
861 * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver,
862 * String, SQLiteQuery)}.
863 */
864 public Cursor newCursor(SQLiteDatabase db,
865 SQLiteCursorDriver masterQuery, String editTable,
866 SQLiteQuery query);
867 }
868
869 /**
870 * Open the database according to the flags {@link #OPEN_READWRITE}
871 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
872 *
873 * <p>Sets the locale of the database to the the system's current locale.
874 * Call {@link #setLocale} if you would like something else.</p>
875 *
876 * @param path to database file to open and/or create
877 * @param factory an optional factory class that is called to instantiate a
878 * cursor when query is called, or null for default
879 * @param flags to control database access mode
880 * @return the newly opened database
881 * @throws SQLiteException if the database cannot be opened
882 */
883 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700884 return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
885 }
886
887 /**
Vasu Nori74f170f2010-06-01 18:06:18 -0700888 * Open the database according to the flags {@link #OPEN_READWRITE}
889 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
890 *
891 * <p>Sets the locale of the database to the the system's current locale.
892 * Call {@link #setLocale} if you would like something else.</p>
893 *
894 * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
895 * used to handle corruption when sqlite reports database corruption.</p>
896 *
897 * @param path to database file to open and/or create
898 * @param factory an optional factory class that is called to instantiate a
899 * cursor when query is called, or null for default
900 * @param flags to control database access mode
901 * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
902 * when sqlite reports database corruption
903 * @return the newly opened database
904 * @throws SQLiteException if the database cannot be opened
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700905 */
906 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
907 DatabaseErrorHandler errorHandler) {
Vasu Nori6c354da2010-04-26 23:33:39 -0700908 SQLiteDatabase sqliteDatabase = openDatabase(path, factory, flags, errorHandler,
909 (short) 0 /* the main connection handle */);
Vasu Noria8c24902010-06-01 11:30:27 -0700910
911 // set sqlite pagesize to mBlockSize
912 if (sBlockSize == 0) {
913 // TODO: "/data" should be a static final String constant somewhere. it is hardcoded
914 // in several places right now.
915 sBlockSize = new StatFs("/data").getBlockSize();
916 }
917 sqliteDatabase.setPageSize(sBlockSize);
Vasu Nori57feb5d2010-06-22 10:39:04 -0700918 //STOPSHIP - uncomment the following line
919 //sqliteDatabase.setJournalMode(path, "TRUNCATE");
920 // STOPSHIP remove the following lines
Vasu Nori7b04c412010-07-20 10:31:21 -0700921 if (!path.equalsIgnoreCase(MEMORY_DB_PATH)) {
922 sqliteDatabase.enableWriteAheadLogging();
923 }
924 // END STOPSHIP
Vasu Norif9e2bd02010-06-04 16:49:51 -0700925
Vasu Noriccd95442010-05-28 17:04:16 -0700926 // add this database to the list of databases opened in this process
927 ActiveDatabases.addActiveDatabase(sqliteDatabase);
Vasu Noric3849202010-03-09 10:47:25 -0800928 return sqliteDatabase;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 }
930
Vasu Nori6c354da2010-04-26 23:33:39 -0700931 private static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
932 DatabaseErrorHandler errorHandler, short connectionNum) {
933 SQLiteDatabase db = new SQLiteDatabase(path, factory, flags, errorHandler, connectionNum);
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700934 try {
Vasu Nori6c354da2010-04-26 23:33:39 -0700935 // Open the database.
936 db.dbopen(path, flags);
937 db.setLocale(Locale.getDefault());
938 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
939 db.enableSqlTracing(path, connectionNum);
940 }
941 if (SQLiteDebug.DEBUG_SQL_TIME) {
942 db.enableSqlProfiling(path, connectionNum);
943 }
944 return db;
945 } catch (SQLiteDatabaseCorruptException e) {
946 db.mErrorHandler.onCorruption(db);
947 return SQLiteDatabase.openDatabase(path, factory, flags, errorHandler);
948 } catch (SQLiteException e) {
949 Log.e(TAG, "Failed to open the database. closing it.", e);
950 db.close();
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700951 throw e;
952 }
953 }
954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 /**
956 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
957 */
958 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
959 return openOrCreateDatabase(file.getPath(), factory);
960 }
961
962 /**
963 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
964 */
965 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
966 return openDatabase(path, factory, CREATE_IF_NECESSARY);
967 }
968
969 /**
Vasu Nori6c354da2010-04-26 23:33:39 -0700970 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler).
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700971 */
972 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,
973 DatabaseErrorHandler errorHandler) {
974 return openDatabase(path, factory, CREATE_IF_NECESSARY, errorHandler);
975 }
976
Vasu Noria98cb262010-06-22 13:16:35 -0700977 private void setJournalMode(final String dbPath, final String mode) {
978 // journal mode can be set only for non-memory databases
979 if (!dbPath.equalsIgnoreCase(MEMORY_DB_PATH)) {
980 String s = DatabaseUtils.stringForQuery(this, "PRAGMA journal_mode=" + mode, null);
981 if (!s.equalsIgnoreCase(mode)) {
982 Log.e(TAG, "setting journal_mode to " + mode + " failed for db: " + dbPath +
983 " (on pragma set journal_mode, sqlite returned:" + s);
984 }
985 }
986 }
987
Vasu Nori062fc7ce2010-03-31 16:13:05 -0700988 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 * Create a memory backed SQLite database. Its contents will be destroyed
990 * when the database is closed.
991 *
992 * <p>Sets the locale of the database to the the system's current locale.
993 * Call {@link #setLocale} if you would like something else.</p>
994 *
995 * @param factory an optional factory class that is called to instantiate a
996 * cursor when query is called
997 * @return a SQLiteDatabase object, or null if the database can't be created
998 */
999 public static SQLiteDatabase create(CursorFactory factory) {
1000 // This is a magic string with special meaning for SQLite.
Vasu Noria98cb262010-06-22 13:16:35 -07001001 return openDatabase(MEMORY_DB_PATH, factory, CREATE_IF_NECESSARY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 }
1003
1004 /**
1005 * Close the database.
1006 */
1007 public void close() {
Vasu Norif3cf8a42010-03-23 11:41:44 -07001008 if (!isOpen()) {
1009 return; // already closed
1010 }
Vasu Nori75010102010-07-01 16:23:06 -07001011 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
1012 Log.i(TAG, "closing db: " + mPath + " (connection # " + mConnectionNum);
1013 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 lock();
1015 try {
1016 closeClosable();
Vasu Norifea6f6d2010-05-21 15:36:06 -07001017 // finalize ALL statements queued up so far
1018 closePendingStatements();
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001019 releaseCustomFunctions();
Vasu Norif6373e92010-03-16 10:21:00 -07001020 // close this database instance - regardless of its reference count value
Vasu Noriad239ab2010-06-14 16:58:47 -07001021 dbclose();
Vasu Nori6c354da2010-04-26 23:33:39 -07001022 if (mConnectionPool != null) {
1023 mConnectionPool.close();
1024 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } finally {
1026 unlock();
1027 }
1028 }
1029
1030 private void closeClosable() {
Vasu Noriccd95442010-05-28 17:04:16 -07001031 /* deallocate all compiled SQL statement objects from mCompiledQueries cache.
Vasu Norie495d1f2010-01-06 16:34:19 -08001032 * this should be done before de-referencing all {@link SQLiteClosable} objects
1033 * from this database object because calling
1034 * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
1035 * to be closed. sqlite doesn't let a database close if there are
1036 * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries.
1037 */
1038 deallocCachedSqlStatements();
1039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
1041 while (iter.hasNext()) {
1042 Map.Entry<SQLiteClosable, Object> entry = iter.next();
1043 SQLiteClosable program = entry.getKey();
1044 if (program != null) {
1045 program.onAllReferencesReleasedFromContainer();
1046 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 /**
1051 * Native call to close the database.
1052 */
1053 private native void dbclose();
1054
1055 /**
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001056 * A callback interface for a custom sqlite3 function.
1057 * This can be used to create a function that can be called from
1058 * sqlite3 database triggers.
1059 * @hide
1060 */
1061 public interface CustomFunction {
1062 public void callback(String[] args);
1063 }
1064
1065 /**
1066 * Registers a CustomFunction callback as a function that can be called from
1067 * sqlite3 database triggers.
1068 * @param name the name of the sqlite3 function
1069 * @param numArgs the number of arguments for the function
1070 * @param function callback to call when the function is executed
1071 * @hide
1072 */
1073 public void addCustomFunction(String name, int numArgs, CustomFunction function) {
1074 verifyDbIsOpen();
1075 synchronized (mCustomFunctions) {
1076 int ref = native_addCustomFunction(name, numArgs, function);
1077 if (ref != 0) {
1078 // save a reference to the function for cleanup later
1079 mCustomFunctions.add(new Integer(ref));
1080 } else {
1081 throw new SQLiteException("failed to add custom function " + name);
1082 }
1083 }
1084 }
1085
1086 private void releaseCustomFunctions() {
1087 synchronized (mCustomFunctions) {
1088 for (int i = 0; i < mCustomFunctions.size(); i++) {
1089 Integer function = mCustomFunctions.get(i);
1090 native_releaseCustomFunction(function.intValue());
1091 }
1092 mCustomFunctions.clear();
1093 }
1094 }
1095
1096 // list of CustomFunction references so we can clean up when the database closes
1097 private final ArrayList<Integer> mCustomFunctions =
1098 new ArrayList<Integer>();
1099
1100 private native int native_addCustomFunction(String name, int numArgs, CustomFunction function);
1101 private native void native_releaseCustomFunction(int function);
1102
1103 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 * Gets the database version.
1105 *
1106 * @return the database version
1107 */
1108 public int getVersion() {
Vasu Noriccd95442010-05-28 17:04:16 -07001109 return ((Long) DatabaseUtils.longForQuery(this, "PRAGMA user_version;", null)).intValue();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111
1112 /**
1113 * Sets the database version.
1114 *
1115 * @param version the new database version
1116 */
1117 public void setVersion(int version) {
1118 execSQL("PRAGMA user_version = " + version);
1119 }
1120
1121 /**
1122 * Returns the maximum size the database may grow to.
1123 *
1124 * @return the new maximum database size
1125 */
1126 public long getMaximumSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001127 long pageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count;", null);
1128 return pageCount * getPageSize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
1130
1131 /**
1132 * Sets the maximum size the database will grow to. The maximum size cannot
1133 * be set below the current size.
1134 *
1135 * @param numBytes the maximum database size, in bytes
1136 * @return the new maximum database size
1137 */
1138 public long setMaximumSize(long numBytes) {
Vasu Noriccd95442010-05-28 17:04:16 -07001139 long pageSize = getPageSize();
1140 long numPages = numBytes / pageSize;
1141 // If numBytes isn't a multiple of pageSize, bump up a page
1142 if ((numBytes % pageSize) != 0) {
1143 numPages++;
Vasu Norif3cf8a42010-03-23 11:41:44 -07001144 }
Vasu Noriccd95442010-05-28 17:04:16 -07001145 long newPageCount = DatabaseUtils.longForQuery(this, "PRAGMA max_page_count = " + numPages,
1146 null);
1147 return newPageCount * pageSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 }
1149
1150 /**
1151 * Returns the current database page size, in bytes.
1152 *
1153 * @return the database page size, in bytes
1154 */
1155 public long getPageSize() {
Vasu Noriccd95442010-05-28 17:04:16 -07001156 return DatabaseUtils.longForQuery(this, "PRAGMA page_size;", null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
1158
1159 /**
1160 * Sets the database page size. The page size must be a power of two. This
1161 * method does not work if any data has been written to the database file,
1162 * and must be called right after the database has been created.
1163 *
1164 * @param numBytes the database page size, in bytes
1165 */
1166 public void setPageSize(long numBytes) {
1167 execSQL("PRAGMA page_size = " + numBytes);
1168 }
1169
1170 /**
1171 * Mark this table as syncable. When an update occurs in this table the
1172 * _sync_dirty field will be set to ensure proper syncing operation.
1173 *
1174 * @param table the table to mark as syncable
1175 * @param deletedTable The deleted table that corresponds to the
1176 * syncable table
Vasu Nori95675132010-07-21 16:24:40 -07001177 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 */
Vasu Nori95675132010-07-21 16:24:40 -07001179 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 public void markTableSyncable(String table, String deletedTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182
1183 /**
1184 * Mark this table as syncable, with the _sync_dirty residing in another
1185 * table. When an update occurs in this table the _sync_dirty field of the
1186 * row in updateTable with the _id in foreignKey will be set to
1187 * ensure proper syncing operation.
1188 *
1189 * @param table an update on this table will trigger a sync time removal
1190 * @param foreignKey this is the column in table whose value is an _id in
1191 * updateTable
1192 * @param updateTable this is the table that will have its _sync_dirty
Vasu Nori95675132010-07-21 16:24:40 -07001193 * @deprecated This method no longer serves any useful purpose and has been deprecated.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 */
Vasu Nori95675132010-07-21 16:24:40 -07001195 @Deprecated
1196 public void markTableSyncable(String table, String foreignKey, String updateTable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 }
1198
1199 /**
1200 * Finds the name of the first table, which is editable.
1201 *
1202 * @param tables a list of tables
1203 * @return the first table listed
1204 */
1205 public static String findEditTable(String tables) {
1206 if (!TextUtils.isEmpty(tables)) {
1207 // find the first word terminated by either a space or a comma
1208 int spacepos = tables.indexOf(' ');
1209 int commapos = tables.indexOf(',');
1210
1211 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1212 return tables.substring(0, spacepos);
1213 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1214 return tables.substring(0, commapos);
1215 }
1216 return tables;
1217 } else {
1218 throw new IllegalStateException("Invalid tables");
1219 }
1220 }
1221
1222 /**
1223 * Compiles an SQL statement into a reusable pre-compiled statement object.
1224 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1225 * statement and fill in those values with {@link SQLiteProgram#bindString}
1226 * and {@link SQLiteProgram#bindLong} each time you want to run the
1227 * statement. Statements may not return result sets larger than 1x1.
Vasu Nori2827d6d2010-07-04 00:26:18 -07001228 *<p>
1229 * No two threads should be using the same {@link SQLiteStatement} at the same time.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 *
1231 * @param sql The raw SQL statement, may contain ? for unknown values to be
1232 * bound later.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001233 * @return A pre-compiled {@link SQLiteStatement} object. Note that
1234 * {@link SQLiteStatement}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 */
1236 public SQLiteStatement compileStatement(String sql) throws SQLException {
Vasu Noriccd95442010-05-28 17:04:16 -07001237 verifyDbIsOpen();
Vasu Nori2827d6d2010-07-04 00:26:18 -07001238 return new SQLiteStatement(this, sql);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 }
1240
1241 /**
1242 * Query the given URL, returning a {@link Cursor} over the result set.
1243 *
1244 * @param distinct true if you want each row to be unique, false otherwise.
1245 * @param table The table name to compile the query against.
1246 * @param columns A list of which columns to return. Passing null will
1247 * return all columns, which is discouraged to prevent reading
1248 * data from storage that isn't going to be used.
1249 * @param selection A filter declaring which rows to return, formatted as an
1250 * SQL WHERE clause (excluding the WHERE itself). Passing null
1251 * will return all rows for the given table.
1252 * @param selectionArgs You may include ?s in selection, which will be
1253 * replaced by the values from selectionArgs, in order that they
1254 * appear in the selection. The values will be bound as Strings.
1255 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1256 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1257 * will cause the rows to not be grouped.
1258 * @param having A filter declare which row groups to include in the cursor,
1259 * if row grouping is being used, formatted as an SQL HAVING
1260 * clause (excluding the HAVING itself). Passing null will cause
1261 * all row groups to be included, and is required when row
1262 * grouping is not being used.
1263 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1264 * (excluding the ORDER BY itself). Passing null will use the
1265 * default sort order, which may be unordered.
1266 * @param limit Limits the number of rows returned by the query,
1267 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001268 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1269 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 * @see Cursor
1271 */
1272 public Cursor query(boolean distinct, String table, String[] columns,
1273 String selection, String[] selectionArgs, String groupBy,
1274 String having, String orderBy, String limit) {
1275 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1276 groupBy, having, orderBy, limit);
1277 }
1278
1279 /**
1280 * Query the given URL, returning a {@link Cursor} over the result set.
1281 *
1282 * @param cursorFactory the cursor factory to use, or null for the default factory
1283 * @param distinct true if you want each row to be unique, false otherwise.
1284 * @param table The table name to compile the query against.
1285 * @param columns A list of which columns to return. Passing null will
1286 * return all columns, which is discouraged to prevent reading
1287 * data from storage that isn't going to be used.
1288 * @param selection A filter declaring which rows to return, formatted as an
1289 * SQL WHERE clause (excluding the WHERE itself). Passing null
1290 * will return all rows for the given table.
1291 * @param selectionArgs You may include ?s in selection, which will be
1292 * replaced by the values from selectionArgs, in order that they
1293 * appear in the selection. The values will be bound as Strings.
1294 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1295 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1296 * will cause the rows to not be grouped.
1297 * @param having A filter declare which row groups to include in the cursor,
1298 * if row grouping is being used, formatted as an SQL HAVING
1299 * clause (excluding the HAVING itself). Passing null will cause
1300 * all row groups to be included, and is required when row
1301 * grouping is not being used.
1302 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1303 * (excluding the ORDER BY itself). Passing null will use the
1304 * default sort order, which may be unordered.
1305 * @param limit Limits the number of rows returned by the query,
1306 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001307 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1308 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 * @see Cursor
1310 */
1311 public Cursor queryWithFactory(CursorFactory cursorFactory,
1312 boolean distinct, String table, String[] columns,
1313 String selection, String[] selectionArgs, String groupBy,
1314 String having, String orderBy, String limit) {
Vasu Noriccd95442010-05-28 17:04:16 -07001315 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 String sql = SQLiteQueryBuilder.buildQueryString(
1317 distinct, table, columns, selection, groupBy, having, orderBy, limit);
1318
1319 return rawQueryWithFactory(
1320 cursorFactory, sql, selectionArgs, findEditTable(table));
1321 }
1322
1323 /**
1324 * Query the given table, returning a {@link Cursor} over the result set.
1325 *
1326 * @param table The table name to compile the query against.
1327 * @param columns A list of which columns to return. Passing null will
1328 * return all columns, which is discouraged to prevent reading
1329 * data from storage that isn't going to be used.
1330 * @param selection A filter declaring which rows to return, formatted as an
1331 * SQL WHERE clause (excluding the WHERE itself). Passing null
1332 * will return all rows for the given table.
1333 * @param selectionArgs You may include ?s in selection, which will be
1334 * replaced by the values from selectionArgs, in order that they
1335 * appear in the selection. The values will be bound as Strings.
1336 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1337 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1338 * will cause the rows to not be grouped.
1339 * @param having A filter declare which row groups to include in the cursor,
1340 * if row grouping is being used, formatted as an SQL HAVING
1341 * clause (excluding the HAVING itself). Passing null will cause
1342 * all row groups to be included, and is required when row
1343 * grouping is not being used.
1344 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1345 * (excluding the ORDER BY itself). Passing null will use the
1346 * default sort order, which may be unordered.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001347 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1348 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 * @see Cursor
1350 */
1351 public Cursor query(String table, String[] columns, String selection,
1352 String[] selectionArgs, String groupBy, String having,
1353 String orderBy) {
1354
1355 return query(false, table, columns, selection, selectionArgs, groupBy,
1356 having, orderBy, null /* limit */);
1357 }
1358
1359 /**
1360 * Query the given table, returning a {@link Cursor} over the result set.
1361 *
1362 * @param table The table name to compile the query against.
1363 * @param columns A list of which columns to return. Passing null will
1364 * return all columns, which is discouraged to prevent reading
1365 * data from storage that isn't going to be used.
1366 * @param selection A filter declaring which rows to return, formatted as an
1367 * SQL WHERE clause (excluding the WHERE itself). Passing null
1368 * will return all rows for the given table.
1369 * @param selectionArgs You may include ?s in selection, which will be
1370 * replaced by the values from selectionArgs, in order that they
1371 * appear in the selection. The values will be bound as Strings.
1372 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1373 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1374 * will cause the rows to not be grouped.
1375 * @param having A filter declare which row groups to include in the cursor,
1376 * if row grouping is being used, formatted as an SQL HAVING
1377 * clause (excluding the HAVING itself). Passing null will cause
1378 * all row groups to be included, and is required when row
1379 * grouping is not being used.
1380 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1381 * (excluding the ORDER BY itself). Passing null will use the
1382 * default sort order, which may be unordered.
1383 * @param limit Limits the number of rows returned by the query,
1384 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001385 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1386 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 * @see Cursor
1388 */
1389 public Cursor query(String table, String[] columns, String selection,
1390 String[] selectionArgs, String groupBy, String having,
1391 String orderBy, String limit) {
1392
1393 return query(false, table, columns, selection, selectionArgs, groupBy,
1394 having, orderBy, limit);
1395 }
1396
1397 /**
1398 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1399 *
1400 * @param sql the SQL query. The SQL string must not be ; terminated
1401 * @param selectionArgs You may include ?s in where clause in the query,
1402 * which will be replaced by the values from selectionArgs. The
1403 * values will be bound as Strings.
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001404 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1405 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 */
1407 public Cursor rawQuery(String sql, String[] selectionArgs) {
1408 return rawQueryWithFactory(null, sql, selectionArgs, null);
1409 }
1410
1411 /**
1412 * Runs the provided SQL and returns a cursor over the result set.
1413 *
1414 * @param cursorFactory the cursor factory to use, or null for the default factory
1415 * @param sql the SQL query. The SQL string must not be ; terminated
1416 * @param selectionArgs You may include ?s in where clause in the query,
1417 * which will be replaced by the values from selectionArgs. The
1418 * values will be bound as Strings.
1419 * @param editTable the name of the first table, which is editable
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001420 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1421 * {@link Cursor}s are not synchronized, see the documentation for more details.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 */
1423 public Cursor rawQueryWithFactory(
1424 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1425 String editTable) {
Vasu Noriccd95442010-05-28 17:04:16 -07001426 verifyDbIsOpen();
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001427 BlockGuard.getThreadPolicy().onReadFromDisk();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 long timeStart = 0;
1429
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001430 if (Config.LOGV || mSlowQueryThreshold != -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 timeStart = System.currentTimeMillis();
1432 }
1433
Vasu Nori6c354da2010-04-26 23:33:39 -07001434 SQLiteDatabase db = getDbConnection(sql);
1435 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(db, sql, editTable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001437 Cursor cursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 try {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001439 cursor = driver.query(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 cursorFactory != null ? cursorFactory : mFactory,
1441 selectionArgs);
1442 } finally {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001443 if (Config.LOGV || mSlowQueryThreshold != -1) {
1444
Vasu Nori020e5342010-04-28 14:22:38 -07001445 // Force query execution
1446 int count = -1;
1447 if (cursor != null) {
1448 count = cursor.getCount();
1449 }
1450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 long duration = System.currentTimeMillis() - timeStart;
1452
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001453 if (Config.LOGV || duration >= mSlowQueryThreshold) {
1454 Log.v(SQLiteCursor.TAG,
1455 "query (" + duration + " ms): " + driver.toString() + ", args are "
1456 + (selectionArgs != null
1457 ? TextUtils.join(",", selectionArgs)
Vasu Nori020e5342010-04-28 14:22:38 -07001458 : "<null>") + ", count is " + count);
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
Vasu Nori6c354da2010-04-26 23:33:39 -07001461 releaseDbConnection(db);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001463 return cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 }
1465
1466 /**
1467 * Runs the provided SQL and returns a cursor over the result set.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001468 * The cursor will read an initial set of rows and the return to the caller.
1469 * It will continue to read in batches and send data changed notifications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 * when the later batches are ready.
1471 * @param sql the SQL query. The SQL string must not be ; terminated
1472 * @param selectionArgs You may include ?s in where clause in the query,
1473 * which will be replaced by the values from selectionArgs. The
1474 * values will be bound as Strings.
1475 * @param initialRead set the initial count of items to read from the cursor
1476 * @param maxRead set the count of items to read on each iteration after the first
Jeff Hamiltonf3ca9a52010-05-12 15:04:33 -07001477 * @return A {@link Cursor} object, which is positioned before the first entry. Note that
1478 * {@link Cursor}s are not synchronized, see the documentation for more details.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001479 *
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001480 * This work is incomplete and not fully tested or reviewed, so currently
1481 * hidden.
1482 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001484 public Cursor rawQuery(String sql, String[] selectionArgs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 int initialRead, int maxRead) {
1486 SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1487 null, sql, selectionArgs, null);
1488 c.setLoadStyle(initialRead, maxRead);
1489 return c;
1490 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 /**
1493 * Convenience method for inserting a row into the database.
1494 *
1495 * @param table the table to insert the row into
1496 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1497 * so if initialValues is empty this column will explicitly be
1498 * assigned a NULL value
1499 * @param values this map contains the initial column values for the
1500 * row. The keys should be the column names and the values the
1501 * column values
1502 * @return the row ID of the newly inserted row, or -1 if an error occurred
1503 */
1504 public long insert(String table, String nullColumnHack, ContentValues values) {
1505 try {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001506 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 } catch (SQLException e) {
1508 Log.e(TAG, "Error inserting " + values, e);
1509 return -1;
1510 }
1511 }
1512
1513 /**
1514 * Convenience method for inserting a row into the database.
1515 *
1516 * @param table the table to insert the row into
1517 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1518 * so if initialValues is empty this column will explicitly be
1519 * assigned a NULL value
1520 * @param values this map contains the initial column values for the
1521 * row. The keys should be the column names and the values the
1522 * column values
1523 * @throws SQLException
1524 * @return the row ID of the newly inserted row, or -1 if an error occurred
1525 */
1526 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1527 throws SQLException {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001528 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 }
1530
1531 /**
1532 * Convenience method for replacing a row in the database.
1533 *
1534 * @param table the table in which to replace the row
1535 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1536 * so if initialValues is empty this row will explicitly be
1537 * assigned a NULL value
1538 * @param initialValues this map contains the initial column values for
1539 * the row. The key
1540 * @return the row ID of the newly inserted row, or -1 if an error occurred
1541 */
1542 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1543 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001544 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001545 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 } catch (SQLException e) {
1547 Log.e(TAG, "Error inserting " + initialValues, e);
1548 return -1;
1549 }
1550 }
1551
1552 /**
1553 * Convenience method for replacing a row in the database.
1554 *
1555 * @param table the table in which to replace the row
1556 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1557 * so if initialValues is empty this row will explicitly be
1558 * assigned a NULL value
1559 * @param initialValues this map contains the initial column values for
1560 * the row. The key
1561 * @throws SQLException
1562 * @return the row ID of the newly inserted row, or -1 if an error occurred
1563 */
1564 public long replaceOrThrow(String table, String nullColumnHack,
1565 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001566 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001567 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 }
1569
1570 /**
1571 * General method for inserting a row into the database.
1572 *
1573 * @param table the table to insert the row into
1574 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1575 * so if initialValues is empty this column will explicitly be
1576 * assigned a NULL value
1577 * @param initialValues this map contains the initial column values for the
1578 * row. The keys should be the column names and the values the
1579 * column values
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001580 * @param conflictAlgorithm for insert conflict resolver
Vasu Nori6eb7c452010-01-27 14:31:24 -08001581 * @return the row ID of the newly inserted row
1582 * OR the primary key of the existing row if the input param 'conflictAlgorithm' =
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001583 * {@link #CONFLICT_IGNORE}
Vasu Nori6eb7c452010-01-27 14:31:24 -08001584 * OR -1 if any error
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 */
1586 public long insertWithOnConflict(String table, String nullColumnHack,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001587 ContentValues initialValues, int conflictAlgorithm) {
Vasu Noriccd95442010-05-28 17:04:16 -07001588 verifyDbIsOpen();
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001589 BlockGuard.getThreadPolicy().onWriteToDisk();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590
1591 // Measurements show most sql lengths <= 152
1592 StringBuilder sql = new StringBuilder(152);
1593 sql.append("INSERT");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001594 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 sql.append(" INTO ");
1596 sql.append(table);
1597 // Measurements show most values lengths < 40
1598 StringBuilder values = new StringBuilder(40);
1599
1600 Set<Map.Entry<String, Object>> entrySet = null;
1601 if (initialValues != null && initialValues.size() > 0) {
1602 entrySet = initialValues.valueSet();
1603 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1604 sql.append('(');
1605
1606 boolean needSeparator = false;
1607 while (entriesIter.hasNext()) {
1608 if (needSeparator) {
1609 sql.append(", ");
1610 values.append(", ");
1611 }
1612 needSeparator = true;
1613 Map.Entry<String, Object> entry = entriesIter.next();
1614 sql.append(entry.getKey());
1615 values.append('?');
1616 }
1617
1618 sql.append(')');
1619 } else {
1620 sql.append("(" + nullColumnHack + ") ");
1621 values.append("NULL");
1622 }
1623
1624 sql.append(" VALUES(");
1625 sql.append(values);
1626 sql.append(");");
1627
1628 lock();
1629 SQLiteStatement statement = null;
1630 try {
1631 statement = compileStatement(sql.toString());
1632
1633 // Bind the values
1634 if (entrySet != null) {
1635 int size = entrySet.size();
1636 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1637 for (int i = 0; i < size; i++) {
1638 Map.Entry<String, Object> entry = entriesIter.next();
1639 DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1640 }
1641 }
1642
1643 // Run the program and then cleanup
1644 statement.execute();
1645
1646 long insertedRowId = lastInsertRow();
1647 if (insertedRowId == -1) {
1648 Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1649 } else {
1650 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1651 Log.v(TAG, "Inserting row " + insertedRowId + " from "
1652 + initialValues + " using " + sql);
1653 }
1654 }
1655 return insertedRowId;
1656 } catch (SQLiteDatabaseCorruptException e) {
1657 onCorruption();
1658 throw e;
1659 } finally {
1660 if (statement != null) {
1661 statement.close();
1662 }
1663 unlock();
1664 }
1665 }
1666
1667 /**
1668 * Convenience method for deleting rows in the database.
1669 *
1670 * @param table the table to delete from
1671 * @param whereClause the optional WHERE clause to apply when deleting.
1672 * Passing null will delete all rows.
1673 * @return the number of rows affected if a whereClause is passed in, 0
1674 * otherwise. To remove all rows and get a count pass "1" as the
1675 * whereClause.
1676 */
1677 public int delete(String table, String whereClause, String[] whereArgs) {
Vasu Noriccd95442010-05-28 17:04:16 -07001678 verifyDbIsOpen();
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001679 BlockGuard.getThreadPolicy().onWriteToDisk();
Vasu Noric8e1f232010-04-13 15:05:09 -07001680 lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 SQLiteStatement statement = null;
1682 try {
1683 statement = compileStatement("DELETE FROM " + table
1684 + (!TextUtils.isEmpty(whereClause)
1685 ? " WHERE " + whereClause : ""));
1686 if (whereArgs != null) {
1687 int numArgs = whereArgs.length;
1688 for (int i = 0; i < numArgs; i++) {
1689 DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1690 }
1691 }
1692 statement.execute();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 return lastChangeCount();
1694 } catch (SQLiteDatabaseCorruptException e) {
1695 onCorruption();
1696 throw e;
1697 } finally {
1698 if (statement != null) {
1699 statement.close();
1700 }
1701 unlock();
1702 }
1703 }
1704
1705 /**
1706 * Convenience method for updating rows in the database.
1707 *
1708 * @param table the table to update in
1709 * @param values a map from column names to new column values. null is a
1710 * valid value that will be translated to NULL.
1711 * @param whereClause the optional WHERE clause to apply when updating.
1712 * Passing null will update all rows.
1713 * @return the number of rows affected
1714 */
1715 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001716 return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 /**
1720 * Convenience method for updating rows in the database.
1721 *
1722 * @param table the table to update in
1723 * @param values a map from column names to new column values. null is a
1724 * valid value that will be translated to NULL.
1725 * @param whereClause the optional WHERE clause to apply when updating.
1726 * Passing null will update all rows.
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001727 * @param conflictAlgorithm for update conflict resolver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 * @return the number of rows affected
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001730 public int updateWithOnConflict(String table, ContentValues values,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001731 String whereClause, String[] whereArgs, int conflictAlgorithm) {
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001732 BlockGuard.getThreadPolicy().onWriteToDisk();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 if (values == null || values.size() == 0) {
1734 throw new IllegalArgumentException("Empty values");
1735 }
1736
1737 StringBuilder sql = new StringBuilder(120);
1738 sql.append("UPDATE ");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001739 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 sql.append(table);
1741 sql.append(" SET ");
1742
1743 Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1744 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1745
1746 while (entriesIter.hasNext()) {
1747 Map.Entry<String, Object> entry = entriesIter.next();
1748 sql.append(entry.getKey());
1749 sql.append("=?");
1750 if (entriesIter.hasNext()) {
1751 sql.append(", ");
1752 }
1753 }
1754
1755 if (!TextUtils.isEmpty(whereClause)) {
1756 sql.append(" WHERE ");
1757 sql.append(whereClause);
1758 }
1759
Vasu Noriccd95442010-05-28 17:04:16 -07001760 verifyDbIsOpen();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 lock();
1762 SQLiteStatement statement = null;
1763 try {
1764 statement = compileStatement(sql.toString());
1765
1766 // Bind the values
1767 int size = entrySet.size();
1768 entriesIter = entrySet.iterator();
1769 int bindArg = 1;
1770 for (int i = 0; i < size; i++) {
1771 Map.Entry<String, Object> entry = entriesIter.next();
1772 DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1773 bindArg++;
1774 }
1775
1776 if (whereArgs != null) {
1777 size = whereArgs.length;
1778 for (int i = 0; i < size; i++) {
1779 statement.bindString(bindArg, whereArgs[i]);
1780 bindArg++;
1781 }
1782 }
1783
1784 // Run the program and then cleanup
1785 statement.execute();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 int numChangedRows = lastChangeCount();
1787 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1788 Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1789 }
1790 return numChangedRows;
1791 } catch (SQLiteDatabaseCorruptException e) {
1792 onCorruption();
1793 throw e;
1794 } catch (SQLException e) {
1795 Log.e(TAG, "Error updating " + values + " using " + sql);
1796 throw e;
1797 } finally {
1798 if (statement != null) {
1799 statement.close();
1800 }
1801 unlock();
1802 }
1803 }
1804
1805 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001806 * Execute a single SQL statement that is NOT a SELECT
1807 * or any other SQL statement that returns data.
1808 * <p>
1809 * Use of this method is discouraged as it doesn't perform well when issuing the same SQL
1810 * statement repeatedly (see {@link #compileStatement(String)} to prepare statements for
1811 * repeated use), and it has no means to return any data (such as the number of affected rows).
1812 * Instead, you're encouraged to use {@link #insert(String, String, ContentValues)},
1813 * {@link #update(String, ContentValues, String, String[])}, et al, when possible.
1814 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001815 * <p>
1816 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1817 * automatically managed by this class. So, do not set journal_mode
1818 * using "PRAGMA journal_mode'<value>" statement if your app is using
1819 * {@link #enableWriteAheadLogging()}
1820 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 *
Vasu Noriccd95442010-05-28 17:04:16 -07001822 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1823 * not supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 * @throws SQLException If the SQL string is invalid for some reason
1825 */
1826 public void execSQL(String sql) throws SQLException {
Vasu Nori8d111032010-06-22 18:34:21 -07001827 sql = sql.trim();
1828 String prefix = sql.substring(0, 6);
1829 if (prefix.equalsIgnoreCase("ATTACH")) {
1830 disableWriteAheadLogging();
1831 }
Vasu Noriccd95442010-05-28 17:04:16 -07001832 verifyDbIsOpen();
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001833 BlockGuard.getThreadPolicy().onWriteToDisk();
Vasu Noric8e1f232010-04-13 15:05:09 -07001834 long timeStart = SystemClock.uptimeMillis();
1835 lock();
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001836 logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 try {
Vasu Nori6f37f832010-05-19 11:53:25 -07001838 closePendingStatements();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 native_execSQL(sql);
1840 } catch (SQLiteDatabaseCorruptException e) {
1841 onCorruption();
1842 throw e;
1843 } finally {
1844 unlock();
1845 }
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001846
1847 // Log commit statements along with the most recently executed
1848 // SQL statement for disambiguation. Note that instance
1849 // equality to COMMIT_SQL is safe here.
1850 if (sql == COMMIT_SQL) {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001851 logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL);
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001852 } else {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07001853 logTimeStat(sql, timeStart, null);
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08001854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 }
1856
1857 /**
Vasu Noriccd95442010-05-28 17:04:16 -07001858 * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
1859 * <p>
1860 * For INSERT statements, use any of the following instead.
1861 * <ul>
1862 * <li>{@link #insert(String, String, ContentValues)}</li>
1863 * <li>{@link #insertOrThrow(String, String, ContentValues)}</li>
1864 * <li>{@link #insertWithOnConflict(String, String, ContentValues, int)}</li>
1865 * </ul>
1866 * <p>
1867 * For UPDATE statements, use any of the following instead.
1868 * <ul>
1869 * <li>{@link #update(String, ContentValues, String, String[])}</li>
1870 * <li>{@link #updateWithOnConflict(String, ContentValues, String, String[], int)}</li>
1871 * </ul>
1872 * <p>
1873 * For DELETE statements, use any of the following instead.
1874 * <ul>
1875 * <li>{@link #delete(String, String, String[])}</li>
1876 * </ul>
1877 * <p>
1878 * For example, the following are good candidates for using this method:
1879 * <ul>
1880 * <li>ALTER TABLE</li>
1881 * <li>CREATE or DROP table / trigger / view / index / virtual table</li>
1882 * <li>REINDEX</li>
1883 * <li>RELEASE</li>
1884 * <li>SAVEPOINT</li>
1885 * <li>PRAGMA that returns no data</li>
1886 * </ul>
1887 * </p>
Vasu Nori9bf225e2010-07-07 16:38:28 -07001888 * <p>
1889 * When using {@link #enableWriteAheadLogging()}, journal_mode is
1890 * automatically managed by this class. So, do not set journal_mode
1891 * using "PRAGMA journal_mode'<value>" statement if your app is using
1892 * {@link #enableWriteAheadLogging()}
1893 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 *
Vasu Noriccd95442010-05-28 17:04:16 -07001895 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
1896 * not supported.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1898 * @throws SQLException If the SQL string is invalid for some reason
1899 */
1900 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
Brad Fitzpatrickcfda9f32010-06-03 12:52:54 -07001901 BlockGuard.getThreadPolicy().onWriteToDisk();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 if (bindArgs == null) {
1903 throw new IllegalArgumentException("Empty bindArgs");
1904 }
Vasu Noriccd95442010-05-28 17:04:16 -07001905 verifyDbIsOpen();
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08001906 long timeStart = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 lock();
1908 SQLiteStatement statement = null;
1909 try {
1910 statement = compileStatement(sql);
1911 if (bindArgs != null) {
1912 int numArgs = bindArgs.length;
1913 for (int i = 0; i < numArgs; i++) {
1914 DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1915 }
1916 }
1917 statement.execute();
1918 } catch (SQLiteDatabaseCorruptException e) {
1919 onCorruption();
1920 throw e;
1921 } finally {
1922 if (statement != null) {
1923 statement.close();
1924 }
1925 unlock();
1926 }
Dan Egnor12311952009-11-23 14:47:45 -08001927 logTimeStat(sql, timeStart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 }
1929
1930 @Override
Mike Lockwood9d9c1be2010-07-13 19:27:52 -04001931 protected void finalize() throws Throwable {
1932 try {
1933 if (isOpen()) {
1934 Log.e(TAG, "close() was never explicitly called on database '" +
1935 mPath + "' ", mStackTrace);
1936 closeClosable();
1937 onAllReferencesReleased();
1938 releaseCustomFunctions();
1939 }
1940 } finally {
1941 super.finalize();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 }
1943 }
1944
1945 /**
Vasu Nori21343692010-06-03 16:01:39 -07001946 * Private constructor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 *
1948 * @param path The full path to the database
1949 * @param factory The factory to use when creating cursors, may be NULL.
1950 * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
1951 * exists, mFlags will be updated appropriately.
Vasu Nori21343692010-06-03 16:01:39 -07001952 * @param errorHandler The {@link DatabaseErrorHandler} to be used when sqlite reports database
1953 * corruption. may be NULL.
Vasu Nori6c354da2010-04-26 23:33:39 -07001954 * @param connectionNum 0 for main database connection handle. 1..N for pooled database
1955 * connection handles.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 */
Vasu Nori21343692010-06-03 16:01:39 -07001957 private SQLiteDatabase(String path, CursorFactory factory, int flags,
Vasu Nori6c354da2010-04-26 23:33:39 -07001958 DatabaseErrorHandler errorHandler, short connectionNum) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 if (path == null) {
1960 throw new IllegalArgumentException("path should not be null");
1961 }
1962 mFlags = flags;
1963 mPath = path;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001964 mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
Vasu Nori08b448e2010-03-03 10:05:16 -08001965 mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 mFactory = factory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 mPrograms = new WeakHashMap<SQLiteClosable,Object>();
Vasu Nori21343692010-06-03 16:01:39 -07001968 // Set the DatabaseErrorHandler to be used when SQLite reports corruption.
1969 // If the caller sets errorHandler = null, then use default errorhandler.
1970 mErrorHandler = (errorHandler == null) ? new DefaultDatabaseErrorHandler() : errorHandler;
Vasu Nori6c354da2010-04-26 23:33:39 -07001971 mConnectionNum = connectionNum;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 }
1973
1974 /**
1975 * return whether the DB is opened as read only.
1976 * @return true if DB is opened as read only
1977 */
1978 public boolean isReadOnly() {
1979 return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1980 }
1981
1982 /**
1983 * @return true if the DB is currently open (has not been closed)
1984 */
1985 public boolean isOpen() {
1986 return mNativeHandle != 0;
1987 }
1988
1989 public boolean needUpgrade(int newVersion) {
1990 return newVersion > getVersion();
1991 }
1992
1993 /**
1994 * Getter for the path to the database file.
1995 *
1996 * @return the path to our database file.
1997 */
1998 public final String getPath() {
1999 return mPath;
2000 }
2001
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08002002 /* package */ void logTimeStat(String sql, long beginMillis) {
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002003 logTimeStat(sql, beginMillis, null);
2004 }
2005
2006 /* package */ void logTimeStat(String sql, long beginMillis, String prefix) {
Brad Fitzpatrickb28c7972010-02-12 12:49:41 -08002007 // Keep track of the last statement executed here, as this is
2008 // the common funnel through which all methods of hitting
2009 // libsqlite eventually flow.
2010 mLastSqlStatement = sql;
2011
Dan Egnor12311952009-11-23 14:47:45 -08002012 // Sample fast queries in proportion to the time taken.
2013 // Quantize the % first, so the logged sampling probability
2014 // exactly equals the actual sampling rate for this query.
2015
2016 int samplePercent;
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08002017 long durationMillis = SystemClock.uptimeMillis() - beginMillis;
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002018 if (durationMillis == 0 && prefix == GET_LOCK_LOG_PREFIX) {
2019 // The common case is locks being uncontended. Don't log those,
2020 // even at 1%, which is our default below.
2021 return;
2022 }
2023 if (sQueryLogTimeInMillis == 0) {
2024 sQueryLogTimeInMillis = SystemProperties.getInt("db.db_operation.threshold_ms", 500);
2025 }
2026 if (durationMillis >= sQueryLogTimeInMillis) {
Dan Egnor12311952009-11-23 14:47:45 -08002027 samplePercent = 100;
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002028 } else {;
2029 samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1;
Dan Egnor799f7212009-11-24 16:24:44 -08002030 if (mRandom.nextInt(100) >= samplePercent) return;
Dan Egnor12311952009-11-23 14:47:45 -08002031 }
2032
Brad Fitzpatrick722802e2010-03-23 22:22:16 -07002033 // Note: the prefix will be "COMMIT;" or "GETLOCK:" when non-null. We wait to do
2034 // it here so we avoid allocating in the common case.
2035 if (prefix != null) {
2036 sql = prefix + sql;
2037 }
2038
Dan Egnor12311952009-11-23 14:47:45 -08002039 if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
2040
2041 // ActivityThread.currentPackageName() only returns non-null if the
2042 // current thread is an application main thread. This parameter tells
2043 // us whether an event loop is blocked, and if so, which app it is.
2044 //
2045 // Sadly, there's no fast way to determine app name if this is *not* a
2046 // main thread, or when we are invoked via Binder (e.g. ContentProvider).
2047 // Hopefully the full path to the database will be informative enough.
2048
Dianne Hackborn01e4cfc2010-06-24 15:07:24 -07002049 String blockingPackage = AppGlobals.getInitialPackage();
Dan Egnor12311952009-11-23 14:47:45 -08002050 if (blockingPackage == null) blockingPackage = "";
2051
Brad Fitzpatrickd72f7182010-02-11 17:07:51 -08002052 EventLog.writeEvent(
Brad Fitzpatrickd8330232010-02-19 10:59:01 -08002053 EVENT_DB_OPERATION,
2054 getPathForLogs(),
2055 sql,
2056 durationMillis,
2057 blockingPackage,
2058 samplePercent);
2059 }
2060
2061 /**
2062 * Removes email addresses from database filenames before they're
2063 * logged to the EventLog where otherwise apps could potentially
2064 * read them.
2065 */
2066 private String getPathForLogs() {
2067 if (mPathForLogs != null) {
2068 return mPathForLogs;
2069 }
2070 if (mPath == null) {
2071 return null;
2072 }
2073 if (mPath.indexOf('@') == -1) {
2074 mPathForLogs = mPath;
2075 } else {
2076 mPathForLogs = EMAIL_IN_DB_PATTERN.matcher(mPath).replaceAll("XX@YY");
2077 }
2078 return mPathForLogs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 }
2080
2081 /**
2082 * Sets the locale for this database. Does nothing if this database has
2083 * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
2084 * @throws SQLException if the locale could not be set. The most common reason
2085 * for this is that there is no collator available for the locale you requested.
2086 * In this case the database remains unchanged.
2087 */
2088 public void setLocale(Locale locale) {
2089 lock();
2090 try {
2091 native_setLocale(locale.toString(), mFlags);
2092 } finally {
2093 unlock();
2094 }
2095 }
2096
Vasu Noriccd95442010-05-28 17:04:16 -07002097 /* package */ void verifyDbIsOpen() {
Vasu Nori9463f292010-04-30 12:22:18 -07002098 if (!isOpen()) {
Vasu Nori75010102010-07-01 16:23:06 -07002099 throw new IllegalStateException("database " + getPath() + " (conn# " +
2100 mConnectionNum + ") already closed");
Vasu Nori9463f292010-04-30 12:22:18 -07002101 }
Vasu Noriccd95442010-05-28 17:04:16 -07002102 }
2103
2104 /* package */ void verifyLockOwner() {
2105 verifyDbIsOpen();
2106 if (mLockingEnabled && !isDbLockedByCurrentThread()) {
Vasu Nori9463f292010-04-30 12:22:18 -07002107 throw new IllegalStateException("Don't have database lock!");
2108 }
2109 }
2110
Vasu Norie495d1f2010-01-06 16:34:19 -08002111 /*
2112 * ============================================================================
2113 *
2114 * The following methods deal with compiled-sql cache
2115 * ============================================================================
2116 */
2117 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002118 * Adds the given SQL and its compiled-statement-id-returned-by-sqlite to the
Vasu Norie495d1f2010-01-06 16:34:19 -08002119 * cache of compiledQueries attached to 'this'.
Vasu Noriccd95442010-05-28 17:04:16 -07002120 * <p>
2121 * If there is already a {@link SQLiteCompiledSql} in compiledQueries for the given SQL,
Vasu Norie495d1f2010-01-06 16:34:19 -08002122 * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
2123 * mapping is NOT replaced with the new mapping).
2124 */
2125 /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
Vasu Norie495d1f2010-01-06 16:34:19 -08002126 SQLiteCompiledSql compiledSql = null;
2127 synchronized(mCompiledQueries) {
2128 // don't insert the new mapping if a mapping already exists
2129 compiledSql = mCompiledQueries.get(sql);
2130 if (compiledSql != null) {
2131 return;
2132 }
Vasu Nori20f549f2010-04-15 11:25:51 -07002133
Vasu Norie495d1f2010-01-06 16:34:19 -08002134 if (mCompiledQueries.size() == mMaxSqlCacheSize) {
Vasu Nori49d02ac2010-03-05 21:49:30 -08002135 /*
2136 * cache size of {@link #mMaxSqlCacheSize} is not enough for this app.
Vasu Nori20f549f2010-04-15 11:25:51 -07002137 * log a warning.
2138 * chances are it is NOT using ? for bindargs - or cachesize is too small.
Vasu Norie495d1f2010-01-06 16:34:19 -08002139 */
Vasu Nori49d02ac2010-03-05 21:49:30 -08002140 if (++mCacheFullWarnings == MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
2141 Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
Vasu Nori20f549f2010-04-15 11:25:51 -07002142 getPath() + ". Consider increasing cachesize.");
Vasu Nori49d02ac2010-03-05 21:49:30 -08002143 }
Vasu Nori20f549f2010-04-15 11:25:51 -07002144 }
2145 /* add the given SQLiteCompiledSql compiledStatement to cache.
2146 * no need to worry about the cache size - because {@link #mCompiledQueries}
2147 * self-limits its size to {@link #mMaxSqlCacheSize}.
2148 */
2149 mCompiledQueries.put(sql, compiledStatement);
2150 if (SQLiteDebug.DEBUG_SQL_CACHE) {
2151 Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" +
2152 mCompiledQueries.size() + "|" + sql);
Vasu Norie495d1f2010-01-06 16:34:19 -08002153 }
Vasu Norie495d1f2010-01-06 16:34:19 -08002154 }
Vasu Norie495d1f2010-01-06 16:34:19 -08002155 }
2156
Vasu Norie495d1f2010-01-06 16:34:19 -08002157 private void deallocCachedSqlStatements() {
2158 synchronized (mCompiledQueries) {
2159 for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
2160 compiledSql.releaseSqlStatement();
2161 }
2162 mCompiledQueries.clear();
2163 }
2164 }
2165
2166 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002167 * From the compiledQueries cache, returns the compiled-statement-id for the given SQL.
2168 * Returns null, if not found in the cache.
Vasu Norie495d1f2010-01-06 16:34:19 -08002169 */
2170 /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
2171 SQLiteCompiledSql compiledStatement = null;
2172 boolean cacheHit;
2173 synchronized(mCompiledQueries) {
Vasu Norie495d1f2010-01-06 16:34:19 -08002174 cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null;
2175 }
2176 if (cacheHit) {
2177 mNumCacheHits++;
2178 } else {
2179 mNumCacheMisses++;
2180 }
2181
2182 if (SQLiteDebug.DEBUG_SQL_CACHE) {
2183 Log.v(TAG, "|cache_stats|" +
2184 getPath() + "|" + mCompiledQueries.size() +
2185 "|" + mNumCacheHits + "|" + mNumCacheMisses +
Vasu Nori20f549f2010-04-15 11:25:51 -07002186 "|" + cacheHit + "|" + sql);
Vasu Norie495d1f2010-01-06 16:34:19 -08002187 }
2188 return compiledStatement;
2189 }
2190
2191 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002192 * Sets the maximum size of the prepared-statement cache for this database.
Vasu Norie495d1f2010-01-06 16:34:19 -08002193 * (size of the cache = number of compiled-sql-statements stored in the cache).
Vasu Noriccd95442010-05-28 17:04:16 -07002194 *<p>
2195 * Maximum cache size can ONLY be increased from its current size (default = 10).
2196 * If this method is called with smaller size than the current maximum value,
2197 * then IllegalStateException is thrown.
2198 *<p>
2199 * This method is thread-safe.
Vasu Norie495d1f2010-01-06 16:34:19 -08002200 *
Vasu Nori90a367262010-04-12 12:49:09 -07002201 * @param cacheSize the size of the cache. can be (0 to {@link #MAX_SQL_CACHE_SIZE})
2202 * @throws IllegalStateException if input cacheSize > {@link #MAX_SQL_CACHE_SIZE} or
2203 * > the value set with previous setMaxSqlCacheSize() call.
Vasu Norie495d1f2010-01-06 16:34:19 -08002204 */
2205 public synchronized void setMaxSqlCacheSize(int cacheSize) {
2206 if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
2207 throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE);
2208 } else if (cacheSize < mMaxSqlCacheSize) {
2209 throw new IllegalStateException("cannot set cacheSize to a value less than the value " +
2210 "set with previous setMaxSqlCacheSize() call.");
2211 }
2212 mMaxSqlCacheSize = cacheSize;
2213 }
2214
Vasu Nori6c354da2010-04-26 23:33:39 -07002215 /* package */ boolean isSqlInStatementCache(String sql) {
2216 synchronized (mCompiledQueries) {
2217 return mCompiledQueries.containsKey(sql);
2218 }
2219 }
2220
Vasu Nori6f37f832010-05-19 11:53:25 -07002221 /* package */ void finalizeStatementLater(int id) {
2222 if (!isOpen()) {
2223 // database already closed. this statement will already have been finalized.
2224 return;
2225 }
2226 synchronized(mClosedStatementIds) {
2227 if (mClosedStatementIds.contains(id)) {
2228 // this statement id is already queued up for finalization.
2229 return;
2230 }
2231 mClosedStatementIds.add(id);
2232 }
2233 }
2234
2235 /**
2236 * public visibility only for testing. otherwise, package visibility is sufficient
2237 * @hide
2238 */
2239 public void closePendingStatements() {
2240 if (!isOpen()) {
2241 // since this database is already closed, no need to finalize anything.
2242 mClosedStatementIds.clear();
2243 return;
2244 }
2245 verifyLockOwner();
2246 /* to minimize synchronization on mClosedStatementIds, make a copy of the list */
2247 ArrayList<Integer> list = new ArrayList<Integer>(mClosedStatementIds.size());
2248 synchronized(mClosedStatementIds) {
2249 list.addAll(mClosedStatementIds);
2250 mClosedStatementIds.clear();
2251 }
2252 // finalize all the statements from the copied list
2253 int size = list.size();
2254 for (int i = 0; i < size; i++) {
2255 native_finalize(list.get(i));
2256 }
2257 }
2258
2259 /**
2260 * for testing only
2261 * @hide
2262 */
2263 public ArrayList<Integer> getQueuedUpStmtList() {
2264 return mClosedStatementIds;
2265 }
2266
Vasu Nori6c354da2010-04-26 23:33:39 -07002267 /**
2268 * This method enables parallel execution of queries from multiple threads on the same database.
2269 * It does this by opening multiple handles to the database and using a different
2270 * database handle for each query.
2271 * <p>
2272 * If a transaction is in progress on one connection handle and say, a table is updated in the
2273 * transaction, then query on the same table on another connection handle will block for the
2274 * transaction to complete. But this method enables such queries to execute by having them
2275 * return old version of the data from the table. Most often it is the data that existed in the
2276 * table prior to the above transaction updates on that table.
2277 * <p>
2278 * Maximum number of simultaneous handles used to execute queries in parallel is
2279 * dependent upon the device memory and possibly other properties.
2280 * <p>
2281 * After calling this method, execution of queries in parallel is enabled as long as this
2282 * database handle is open. To disable execution of queries in parallel, database should
2283 * be closed and reopened.
2284 * <p>
2285 * If a query is part of a transaction, then it is executed on the same database handle the
2286 * transaction was begun.
Vasu Nori6c354da2010-04-26 23:33:39 -07002287 * <p>
2288 * If the database has any attached databases, then execution of queries in paralel is NOT
Vasu Noria98cb262010-06-22 13:16:35 -07002289 * possible. In such cases, a message is printed to logcat and false is returned.
2290 * <p>
2291 * This feature is not available for :memory: databases. In such cases,
2292 * a message is printed to logcat and false is returned.
Vasu Nori6c354da2010-04-26 23:33:39 -07002293 * <p>
2294 * A typical way to use this method is the following:
2295 * <pre>
2296 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
2297 * CREATE_IF_NECESSARY, myDatabaseErrorHandler);
2298 * db.enableWriteAheadLogging();
2299 * </pre>
2300 * <p>
2301 * Writers should use {@link #beginTransactionNonExclusive()} or
2302 * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
2303 * to start a trsnsaction.
2304 * Non-exclusive mode allows database file to be in readable by threads executing queries.
2305 * </p>
2306 *
Vasu Noria98cb262010-06-22 13:16:35 -07002307 * @return true if write-ahead-logging is set. false otherwise
Vasu Nori6c354da2010-04-26 23:33:39 -07002308 */
Vasu Noria98cb262010-06-22 13:16:35 -07002309 public synchronized boolean enableWriteAheadLogging() {
2310 if (mPath.equalsIgnoreCase(MEMORY_DB_PATH)) {
2311 Log.i(TAG, "can't enable WAL for memory databases.");
2312 return false;
Vasu Nori6c354da2010-04-26 23:33:39 -07002313 }
2314
2315 // make sure this database has NO attached databases because sqlite's write-ahead-logging
2316 // doesn't work for databases with attached databases
2317 if (getAttachedDbs().size() > 1) {
Vasu Noria98cb262010-06-22 13:16:35 -07002318 Log.i(TAG, "this database: " + mPath + " has attached databases. can't enable WAL.");
2319 return false;
Vasu Nori6c354da2010-04-26 23:33:39 -07002320 }
Vasu Noria98cb262010-06-22 13:16:35 -07002321 if (mConnectionPool == null) {
2322 mConnectionPool = new DatabaseConnectionPool(this);
2323 setJournalMode(mPath, "WAL");
Vasu Nori6c354da2010-04-26 23:33:39 -07002324 }
Vasu Noria98cb262010-06-22 13:16:35 -07002325 return true;
Vasu Nori6c354da2010-04-26 23:33:39 -07002326 }
2327
Vasu Nori2827d6d2010-07-04 00:26:18 -07002328 /**
Vasu Nori7b04c412010-07-20 10:31:21 -07002329 * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
2330 * @hide
Vasu Nori2827d6d2010-07-04 00:26:18 -07002331 */
Vasu Nori7b04c412010-07-20 10:31:21 -07002332 public void disableWriteAheadLogging() {
2333 synchronized (this) {
2334 if (mConnectionPool == null) {
2335 return;
2336 }
2337 mConnectionPool.close();
2338 mConnectionPool = null;
2339 setJournalMode(mPath, "TRUNCATE");
Vasu Nori8d111032010-06-22 18:34:21 -07002340 }
Vasu Nori8d111032010-06-22 18:34:21 -07002341 }
2342
Vasu Nori65a88832010-07-16 15:14:08 -07002343 /* package */ SQLiteDatabase getDatabaseHandle(String sql) {
2344 if (isPooledConnection()) {
2345 // this is a pooled database connection
2346 if (isOpen()) {
2347 // TODO: use another connection from the pool
2348 // if this connection is currently in use by some other thread
2349 // AND if there are free connections in the pool
2350 return this;
2351 } else {
2352 // the pooled connection is not open! could have been closed either due
2353 // to corruption on this or some other connection to the database
2354 // OR, maybe the connection pool is disabled after this connection has been
2355 // allocated to me. try to get some other pooled or main database connection
2356 return getParentDbConnObj().getDbConnection(sql);
2357 }
2358 } else {
2359 // this is NOT a pooled connection. can we get one?
2360 return getDbConnection(sql);
2361 }
2362 }
2363
Vasu Nori6c354da2010-04-26 23:33:39 -07002364 /**
2365 * Sets the database connection handle pool size to the given value.
2366 * Database connection handle pool is enabled when the app calls
2367 * {@link #enableWriteAheadLogging()}.
2368 * <p>
2369 * The default connection handle pool is set by the system by taking into account various
2370 * aspects of the device, such as memory, number of cores etc. It is recommended that
2371 * applications use the default pool size set by the system.
2372 *
2373 * @param size the value the connection handle pool size should be set to.
2374 */
2375 public synchronized void setConnectionPoolSize(int size) {
2376 if (mConnectionPool == null) {
2377 throw new IllegalStateException("connection pool not enabled");
2378 }
2379 int i = mConnectionPool.getMaxPoolSize();
2380 if (size < i) {
Vasu Noridaa4e4f2010-06-15 11:32:27 -07002381 throw new IllegalArgumentException(
Vasu Nori6c354da2010-04-26 23:33:39 -07002382 "cannot set max pool size to a value less than the current max value(=" +
2383 i + ")");
2384 }
2385 mConnectionPool.setMaxPoolSize(size);
2386 }
2387
2388 /* package */ SQLiteDatabase createPoolConnection(short connectionNum) {
Vasu Nori65a88832010-07-16 15:14:08 -07002389 SQLiteDatabase db = openDatabase(mPath, mFactory, mFlags, mErrorHandler, connectionNum);
2390 db.mParentConnObj = this;
2391 return db;
2392 }
2393
2394 private synchronized SQLiteDatabase getParentDbConnObj() {
2395 return mParentConnObj;
Vasu Nori6c354da2010-04-26 23:33:39 -07002396 }
2397
2398 private boolean isPooledConnection() {
2399 return this.mConnectionNum > 0;
2400 }
2401
Vasu Nori2827d6d2010-07-04 00:26:18 -07002402 /* package */ SQLiteDatabase getDbConnection(String sql) {
Vasu Nori6c354da2010-04-26 23:33:39 -07002403 verifyDbIsOpen();
Vasu Nori65a88832010-07-16 15:14:08 -07002404 // this method should always be called with main database connection handle
2405 // NEVER with pooled database connection handle
2406 if (isPooledConnection()) {
2407 throw new IllegalStateException("incorrect database connection handle");
2408 }
2409 if (Log.isLoggable(TAG, Log.DEBUG)) {
2410 // this method shoudl never be called with anything other than SELECT
2411 if (sql.substring(0, 6).equalsIgnoreCase("SELECT")) {
2412 throw new IllegalStateException("unexpected SQL statement: " + sql);
2413 }
2414 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002415
2416 // use the current connection handle if
Vasu Nori65a88832010-07-16 15:14:08 -07002417 // 1. if this thread is in a transaction
2418 // 2. OR, if there is NO connection handle pool setup
2419 if ((inTransaction() && mLock.isHeldByCurrentThread()) || mConnectionPool == null) {
2420 return this;
Vasu Nori6c354da2010-04-26 23:33:39 -07002421 } else {
2422 // get a connection handle from the pool
2423 if (Log.isLoggable(TAG, Log.DEBUG)) {
2424 assert mConnectionPool != null;
2425 }
Vasu Nori65a88832010-07-16 15:14:08 -07002426 return mConnectionPool.get(sql);
Vasu Nori6c354da2010-04-26 23:33:39 -07002427 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002428 }
2429
2430 private void releaseDbConnection(SQLiteDatabase db) {
2431 // ignore this release call if
2432 // 1. the database is closed
2433 // 2. OR, if db is NOT a pooled connection handle
2434 // 3. OR, if the database being released is same as 'this' (this condition means
2435 // that we should always be releasing a pooled connection handle by calling this method
2436 // from the 'main' connection handle
2437 if (!isOpen() || !db.isPooledConnection() || (db == this)) {
2438 return;
2439 }
2440 if (Log.isLoggable(TAG, Log.DEBUG)) {
2441 assert isPooledConnection();
2442 assert mConnectionPool != null;
2443 Log.d(TAG, "releaseDbConnection threadid = " + Thread.currentThread().getId() +
2444 ", releasing # " + db.mConnectionNum + ", " + getPath());
2445 }
2446 mConnectionPool.release(db);
2447 }
2448
Vasu Noric3849202010-03-09 10:47:25 -08002449 static class ActiveDatabases {
2450 private static final ActiveDatabases activeDatabases = new ActiveDatabases();
2451 private HashSet<WeakReference<SQLiteDatabase>> mActiveDatabases =
Vasu Noriccd95442010-05-28 17:04:16 -07002452 new HashSet<WeakReference<SQLiteDatabase>>();
Vasu Noric3849202010-03-09 10:47:25 -08002453 private ActiveDatabases() {} // disable instantiation of this class
Vasu Noriccd95442010-05-28 17:04:16 -07002454 static ActiveDatabases getInstance() {
2455 return activeDatabases;
2456 }
2457 private static void addActiveDatabase(SQLiteDatabase sqliteDatabase) {
2458 activeDatabases.mActiveDatabases.add(new WeakReference<SQLiteDatabase>(sqliteDatabase));
2459 }
Vasu Noric3849202010-03-09 10:47:25 -08002460 }
2461
Vasu Norif3cf8a42010-03-23 11:41:44 -07002462 /**
2463 * this method is used to collect data about ALL open databases in the current process.
2464 * bugreport is a user of this data.
2465 */
Vasu Noric3849202010-03-09 10:47:25 -08002466 /* package */ static ArrayList<DbStats> getDbStats() {
2467 ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
2468 for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) {
2469 SQLiteDatabase db = w.get();
2470 if (db == null || !db.isOpen()) {
2471 continue;
2472 }
Vasu Noric3849202010-03-09 10:47:25 -08002473
Vasu Noriccd95442010-05-28 17:04:16 -07002474 try {
2475 // get SQLITE_DBSTATUS_LOOKASIDE_USED for the db
2476 int lookasideUsed = db.native_getDbLookaside();
Vasu Noric3849202010-03-09 10:47:25 -08002477
Vasu Noriccd95442010-05-28 17:04:16 -07002478 // get the lastnode of the dbname
2479 String path = db.getPath();
2480 int indx = path.lastIndexOf("/");
2481 String lastnode = path.substring((indx != -1) ? ++indx : 0);
Vasu Noric3849202010-03-09 10:47:25 -08002482
Vasu Noriccd95442010-05-28 17:04:16 -07002483 // get list of attached dbs and for each db, get its size and pagesize
2484 ArrayList<Pair<String, String>> attachedDbs = db.getAttachedDbs();
2485 if (attachedDbs == null) {
2486 continue;
2487 }
2488 for (int i = 0; i < attachedDbs.size(); i++) {
2489 Pair<String, String> p = attachedDbs.get(i);
2490 long pageCount = DatabaseUtils.longForQuery(db, "PRAGMA " + p.first
2491 + ".page_count;", null);
2492
2493 // first entry in the attached db list is always the main database
2494 // don't worry about prefixing the dbname with "main"
2495 String dbName;
2496 if (i == 0) {
2497 dbName = lastnode;
2498 } else {
2499 // lookaside is only relevant for the main db
2500 lookasideUsed = 0;
2501 dbName = " (attached) " + p.first;
2502 // if the attached db has a path, attach the lastnode from the path to above
2503 if (p.second.trim().length() > 0) {
2504 int idx = p.second.lastIndexOf("/");
2505 dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
2506 }
2507 }
2508 if (pageCount > 0) {
2509 dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
2510 lookasideUsed, db.mNumCacheHits, db.mNumCacheMisses,
2511 db.mCompiledQueries.size()));
Vasu Noric3849202010-03-09 10:47:25 -08002512 }
2513 }
Vasu Nori6c354da2010-04-26 23:33:39 -07002514 // if there are pooled connections, return the cache stats for them also.
2515 if (db.mConnectionPool != null) {
2516 for (SQLiteDatabase pDb : db.mConnectionPool.getConnectionList()) {
2517 dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") "
2518 + lastnode, 0, 0, 0, pDb.mNumCacheHits, pDb.mNumCacheMisses,
2519 pDb.mCompiledQueries.size()));
2520 }
2521 }
Vasu Noriccd95442010-05-28 17:04:16 -07002522 } catch (SQLiteException e) {
2523 // ignore. we don't care about exceptions when we are taking adb
2524 // bugreport!
Vasu Noric3849202010-03-09 10:47:25 -08002525 }
2526 }
2527 return dbStatsList;
2528 }
2529
2530 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002531 * Returns list of full pathnames of all attached databases including the main database
2532 * by executing 'pragma database_list' on the database.
2533 *
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002534 * @return ArrayList of pairs of (database name, database file path) or null if the database
2535 * is not open.
Vasu Noric3849202010-03-09 10:47:25 -08002536 */
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002537 public ArrayList<Pair<String, String>> getAttachedDbs() {
2538 if (!isOpen()) {
Vasu Norif3cf8a42010-03-23 11:41:44 -07002539 return null;
2540 }
Vasu Noric3849202010-03-09 10:47:25 -08002541 ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002542 Cursor c = null;
2543 try {
2544 c = rawQuery("pragma database_list;", null);
2545 while (c.moveToNext()) {
2546 // sqlite returns a row for each database in the returned list of databases.
2547 // in each row,
2548 // 1st column is the database name such as main, or the database
2549 // name specified on the "ATTACH" command
2550 // 2nd column is the database file path.
2551 attachedDbs.add(new Pair<String, String>(c.getString(1), c.getString(2)));
2552 }
2553 } finally {
2554 if (c != null) {
2555 c.close();
2556 }
Vasu Noric3849202010-03-09 10:47:25 -08002557 }
Vasu Noric3849202010-03-09 10:47:25 -08002558 return attachedDbs;
2559 }
2560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002561 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002562 * Runs 'pragma integrity_check' on the given database (and all the attached databases)
2563 * and returns true if the given database (and all its attached databases) pass integrity_check,
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002564 * false otherwise.
Vasu Noriccd95442010-05-28 17:04:16 -07002565 *<p>
2566 * If the result is false, then this method logs the errors reported by the integrity_check
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002567 * command execution.
Vasu Noriccd95442010-05-28 17:04:16 -07002568 *<p>
2569 * Note that 'pragma integrity_check' on a database can take a long time.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002570 *
2571 * @return true if the given database (and all its attached databases) pass integrity_check,
Vasu Noriccd95442010-05-28 17:04:16 -07002572 * false otherwise.
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002573 */
2574 public boolean isDatabaseIntegrityOk() {
Vasu Noriccd95442010-05-28 17:04:16 -07002575 verifyDbIsOpen();
Vasu Nori062fc7ce2010-03-31 16:13:05 -07002576 ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs();
2577 if (attachedDbs == null) {
2578 throw new IllegalStateException("databaselist for: " + getPath() + " couldn't " +
2579 "be retrieved. probably because the database is closed");
2580 }
2581 boolean isDatabaseCorrupt = false;
2582 for (int i = 0; i < attachedDbs.size(); i++) {
2583 Pair<String, String> p = attachedDbs.get(i);
2584 SQLiteStatement prog = null;
2585 try {
2586 prog = compileStatement("PRAGMA " + p.first + ".integrity_check(1);");
2587 String rslt = prog.simpleQueryForString();
2588 if (!rslt.equalsIgnoreCase("ok")) {
2589 // integrity_checker failed on main or attached databases
2590 isDatabaseCorrupt = true;
2591 Log.e(TAG, "PRAGMA integrity_check on " + p.second + " returned: " + rslt);
2592 }
2593 } finally {
2594 if (prog != null) prog.close();
2595 }
2596 }
2597 return isDatabaseCorrupt;
2598 }
2599
2600 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002601 * Native call to open the database.
2602 *
2603 * @param path The full path to the database
2604 */
2605 private native void dbopen(String path, int flags);
2606
2607 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002608 * Native call to setup tracing of all SQL statements
Vasu Nori3ef94e22010-02-05 14:49:04 -08002609 *
2610 * @param path the full path to the database
Vasu Nori6c354da2010-04-26 23:33:39 -07002611 * @param connectionNum connection number: 0 - N, where the main database
2612 * connection handle is numbered 0 and the connection handles in the connection
2613 * pool are numbered 1..N.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002614 */
Vasu Nori6c354da2010-04-26 23:33:39 -07002615 private native void enableSqlTracing(String path, short connectionNum);
Vasu Nori3ef94e22010-02-05 14:49:04 -08002616
2617 /**
Vasu Noriccd95442010-05-28 17:04:16 -07002618 * Native call to setup profiling of all SQL statements.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002619 * currently, sqlite's profiling = printing of execution-time
Vasu Noriccd95442010-05-28 17:04:16 -07002620 * (wall-clock time) of each of the SQL statements, as they
Vasu Nori3ef94e22010-02-05 14:49:04 -08002621 * are executed.
2622 *
2623 * @param path the full path to the database
Vasu Nori6c354da2010-04-26 23:33:39 -07002624 * @param connectionNum connection number: 0 - N, where the main database
2625 * connection handle is numbered 0 and the connection handles in the connection
2626 * pool are numbered 1..N.
Vasu Nori3ef94e22010-02-05 14:49:04 -08002627 */
Vasu Nori6c354da2010-04-26 23:33:39 -07002628 private native void enableSqlProfiling(String path, short connectionNum);
Vasu Nori3ef94e22010-02-05 14:49:04 -08002629
2630 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 * Native call to execute a raw SQL statement. {@link #lock} must be held
2632 * when calling this method.
2633 *
2634 * @param sql The raw SQL string
2635 * @throws SQLException
2636 */
2637 /* package */ native void native_execSQL(String sql) throws SQLException;
2638
2639 /**
2640 * Native call to set the locale. {@link #lock} must be held when calling
2641 * this method.
2642 * @throws SQLException
2643 */
2644 /* package */ native void native_setLocale(String loc, int flags);
2645
2646 /**
2647 * Returns the row ID of the last row inserted into the database.
2648 *
2649 * @return the row ID of the last row inserted into the database.
2650 */
2651 /* package */ native long lastInsertRow();
2652
2653 /**
2654 * Returns the number of changes made in the last statement executed.
2655 *
2656 * @return the number of changes made in the last statement executed.
2657 */
2658 /* package */ native int lastChangeCount();
Vasu Noric3849202010-03-09 10:47:25 -08002659
2660 /**
2661 * return the SQLITE_DBSTATUS_LOOKASIDE_USED documented here
2662 * http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html
2663 * @return int value of SQLITE_DBSTATUS_LOOKASIDE_USED
2664 */
2665 private native int native_getDbLookaside();
Vasu Nori6f37f832010-05-19 11:53:25 -07002666
2667 /**
2668 * finalizes the given statement id.
2669 *
2670 * @param statementId statement to be finzlied by sqlite
2671 */
2672 private final native void native_finalize(int statementId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673}