blob: 540f4445ba1258e55e73d6a8cc7caa880a1cc53b [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
Vasu Nori5a03f362009-10-20 15:16:35 -070019import com.google.android.collect.Maps;
20
Dan Egnor12311952009-11-23 14:47:45 -080021import android.app.ActivityThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.ContentValues;
23import android.database.Cursor;
24import android.database.DatabaseUtils;
25import android.database.SQLException;
26import android.os.Debug;
27import android.os.SystemClock;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070028import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.text.TextUtils;
30import android.util.Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.EventLog;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -070032import android.util.Log;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34import java.io.File;
Vasu Nori5a03f362009-10-20 15:16:35 -070035import java.text.SimpleDateFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import java.util.HashMap;
37import java.util.Iterator;
38import java.util.Locale;
39import java.util.Map;
Dan Egnor12311952009-11-23 14:47:45 -080040import java.util.Random;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import java.util.Set;
42import java.util.WeakHashMap;
43import java.util.concurrent.locks.ReentrantLock;
44
45/**
46 * Exposes methods to manage a SQLite database.
47 * <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
48 * perform other common database management tasks.
49 * <p>See the Notepad sample application in the SDK for an example of creating
50 * and managing a database.
51 * <p> Database names must be unique within an application, not across all
52 * applications.
53 *
54 * <h3>Localized Collation - ORDER BY</h3>
55 * <p>In addition to SQLite's default <code>BINARY</code> collator, Android supplies
56 * two more, <code>LOCALIZED</code>, which changes with the system's current locale
57 * if you wire it up correctly (XXX a link needed!), and <code>UNICODE</code>, which
58 * is the Unicode Collation Algorithm and not tailored to the current locale.
59 */
60public class SQLiteDatabase extends SQLiteClosable {
61 private static final String TAG = "Database";
Jeff Hamilton082c2af2009-09-29 11:49:51 -070062 private static final int EVENT_DB_OPERATION = 52000;
63 private static final int EVENT_DB_CORRUPT = 75004;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
65 /**
66 * Algorithms used in ON CONFLICT clause
67 * http://www.sqlite.org/lang_conflict.html
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 */
Vasu Nori8d45e4e2010-02-05 22:35:47 -080069 /**
70 * When a constraint violation occurs, an immediate ROLLBACK occurs,
71 * thus ending the current transaction, and the command aborts with a
72 * return code of SQLITE_CONSTRAINT. If no transaction is active
73 * (other than the implied transaction that is created on every command)
74 * then this algorithm works the same as ABORT.
75 */
76 public static final int CONFLICT_ROLLBACK = 1;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070077
Vasu Nori8d45e4e2010-02-05 22:35:47 -080078 /**
79 * When a constraint violation occurs,no ROLLBACK is executed
80 * so changes from prior commands within the same transaction
81 * are preserved. This is the default behavior.
82 */
83 public static final int CONFLICT_ABORT = 2;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070084
Vasu Nori8d45e4e2010-02-05 22:35:47 -080085 /**
86 * When a constraint violation occurs, the command aborts with a return
87 * code SQLITE_CONSTRAINT. But any changes to the database that
88 * the command made prior to encountering the constraint violation
89 * are preserved and are not backed out.
90 */
91 public static final int CONFLICT_FAIL = 3;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -070092
Vasu Nori8d45e4e2010-02-05 22:35:47 -080093 /**
94 * When a constraint violation occurs, the one row that contains
95 * the constraint violation is not inserted or changed.
96 * But the command continues executing normally. Other rows before and
97 * after the row that contained the constraint violation continue to be
98 * inserted or updated normally. No error is returned.
99 */
100 public static final int CONFLICT_IGNORE = 4;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700101
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800102 /**
103 * When a UNIQUE constraint violation occurs, the pre-existing rows that
104 * are causing the constraint violation are removed prior to inserting
105 * or updating the current row. Thus the insert or update always occurs.
106 * The command continues executing normally. No error is returned.
107 * If a NOT NULL constraint violation occurs, the NULL value is replaced
108 * by the default value for that column. If the column has no default
109 * value, then the ABORT algorithm is used. If a CHECK constraint
110 * violation occurs then the IGNORE algorithm is used. When this conflict
111 * resolution strategy deletes rows in order to satisfy a constraint,
112 * it does not invoke delete triggers on those rows.
113 * This behavior might change in a future release.
114 */
115 public static final int CONFLICT_REPLACE = 5;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700116
Vasu Nori8d45e4e2010-02-05 22:35:47 -0800117 /**
118 * use the following when no conflict action is specified.
119 */
120 public static final int CONFLICT_NONE = 0;
121 private static final String[] CONFLICT_VALUES = new String[]
122 {"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * Maximum Length Of A LIKE Or GLOB Pattern
126 * The pattern matching algorithm used in the default LIKE and GLOB implementation
127 * of SQLite can exhibit O(N^2) performance (where N is the number of characters in
128 * the pattern) for certain pathological cases. To avoid denial-of-service attacks
129 * the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes.
130 * The default value of this limit is 50000. A modern workstation can evaluate
131 * even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
132 * The denial of service problem only comes into play when the pattern length gets
133 * into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
134 * are at most a few dozen bytes in length, paranoid application developers may
135 * want to reduce this parameter to something in the range of a few hundred
136 * if they know that external users are able to generate arbitrary patterns.
137 */
138 public static final int SQLITE_MAX_LIKE_PATTERN_LENGTH = 50000;
139
140 /**
141 * Flag for {@link #openDatabase} to open the database for reading and writing.
142 * If the disk is full, this may fail even before you actually write anything.
143 *
144 * {@more} Note that the value of this flag is 0, so it is the default.
145 */
146 public static final int OPEN_READWRITE = 0x00000000; // update native code if changing
147
148 /**
149 * Flag for {@link #openDatabase} to open the database for reading only.
150 * This is the only reliable way to open a database if the disk may be full.
151 */
152 public static final int OPEN_READONLY = 0x00000001; // update native code if changing
153
154 private static final int OPEN_READ_MASK = 0x00000001; // update native code if changing
155
156 /**
157 * Flag for {@link #openDatabase} to open the database without support for localized collators.
158 *
159 * {@more} This causes the collator <code>LOCALIZED</code> not to be created.
160 * You must be consistent when using this flag to use the setting the database was
161 * created with. If this is set, {@link #setLocale} will do nothing.
162 */
163 public static final int NO_LOCALIZED_COLLATORS = 0x00000010; // update native code if changing
164
165 /**
166 * Flag for {@link #openDatabase} to create the database file if it does not already exist.
167 */
168 public static final int CREATE_IF_NECESSARY = 0x10000000; // update native code if changing
169
170 /**
171 * Indicates whether the most-recently started transaction has been marked as successful.
172 */
173 private boolean mInnerTransactionIsSuccessful;
174
175 /**
176 * Valid during the life of a transaction, and indicates whether the entire transaction (the
177 * outer one and all of the inner ones) so far has been successful.
178 */
179 private boolean mTransactionIsSuccessful;
180
Fred Quintanac4516a72009-09-03 12:14:06 -0700181 /**
182 * Valid during the life of a transaction.
183 */
184 private SQLiteTransactionListener mTransactionListener;
185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 /** Synchronize on this when accessing the database */
187 private final ReentrantLock mLock = new ReentrantLock(true);
188
189 private long mLockAcquiredWallTime = 0L;
190 private long mLockAcquiredThreadTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 // limit the frequency of complaints about each database to one within 20 sec
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700193 // unless run command adb shell setprop log.tag.Database VERBOSE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final int LOCK_WARNING_WINDOW_IN_MS = 20000;
195 /** If the lock is held this long then a warning will be printed when it is released. */
196 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS = 300;
197 private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
198 private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
199
Dmitri Plotnikovb43b58d2009-09-09 18:10:42 -0700200 private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 private long mLastLockMessageTime = 0L;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700203
Dan Egnor12311952009-11-23 14:47:45 -0800204 // always log queries which take 100ms+; shorter queries are sampled accordingly
205 private static final int QUERY_LOG_TIME_IN_NANOS = 100 * 1000000;
206 private static final int QUERY_LOG_SQL_LENGTH = 64;
207 private final Random mRandom = new Random();
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 /** Used by native code, do not rename */
210 /* package */ int mNativeHandle = 0;
211
212 /** Used to make temp table names unique */
213 /* package */ int mTempTableSequence = 0;
214
215 /** The path for the database file */
216 private String mPath;
217
218 /** The flags passed to open/create */
219 private int mFlags;
220
221 /** The optional factory to use when creating new Cursors */
222 private CursorFactory mFactory;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 private WeakHashMap<SQLiteClosable, Object> mPrograms;
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700225
Vasu Nori5a03f362009-10-20 15:16:35 -0700226 /**
227 * for each instance of this class, a cache is maintained to store
228 * the compiled query statement ids returned by sqlite database.
229 * key = sql statement with "?" for bind args
230 * value = {@link SQLiteCompiledSql}
231 * If an application opens the database and keeps it open during its entire life, then
232 * there will not be an overhead of compilation of sql statements by sqlite.
233 *
234 * why is this cache NOT static? because sqlite attaches compiledsql statements to the
235 * struct created when {@link SQLiteDatabase#openDatabase(String, CursorFactory, int)} is
236 * invoked.
237 *
238 * this cache has an upper limit of mMaxSqlCacheSize (settable by calling the method
239 * (@link setMaxCacheSize(int)}). its default is 0 - i.e., no caching by default because
240 * most of the apps don't use "?" syntax in their sql, caching is not useful for them.
241 */
Vasu Norie495d1f2010-01-06 16:34:19 -0800242 /* package */ Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap();
243 /**
244 * @hide
245 */
246 public static final int MAX_SQL_CACHE_SIZE = 250;
247 private int mMaxSqlCacheSize = MAX_SQL_CACHE_SIZE; // max cache size per Database instance
Vasu Norie9d92102010-01-20 15:07:26 -0800248 private int mCacheFullWarnings;
249 private static final int MAX_WARNINGS_ON_CACHESIZE_CONDITION = 5;
Vasu Nori5a03f362009-10-20 15:16:35 -0700250
251 /** maintain stats about number of cache hits and misses */
252 private int mNumCacheHits;
253 private int mNumCacheMisses;
254
255 /** the following 2 members maintain the time when a database is opened and closed */
256 private String mTimeOpened = null;
257 private String mTimeClosed = null;
258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 private final RuntimeException mLeakedException;
260
Dmitri Plotnikov90142c92009-09-15 10:52:17 -0700261 // System property that enables logging of slow queries. Specify the threshold in ms.
262 private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
263 private final int mSlowQueryThreshold;
264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 /**
266 * @param closable
267 */
268 void addSQLiteClosable(SQLiteClosable closable) {
269 lock();
270 try {
271 mPrograms.put(closable, null);
272 } finally {
273 unlock();
274 }
275 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 void removeSQLiteClosable(SQLiteClosable closable) {
278 lock();
279 try {
280 mPrograms.remove(closable);
281 } finally {
282 unlock();
283 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700284 }
285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 @Override
287 protected void onAllReferencesReleased() {
288 if (isOpen()) {
Vasu Nori5a03f362009-10-20 15:16:35 -0700289 if (SQLiteDebug.DEBUG_SQL_CACHE) {
290 mTimeClosed = getTime();
291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 dbclose();
293 }
294 }
295
296 /**
297 * Attempts to release memory that SQLite holds but does not require to
298 * operate properly. Typically this memory will come from the page cache.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700299 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 * @return the number of bytes actually released
301 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700302 static public native int releaseMemory();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 /**
305 * Control whether or not the SQLiteDatabase is made thread-safe by using locks
306 * around critical sections. This is pretty expensive, so if you know that your
307 * DB will only be used by a single thread then you should set this to false.
308 * The default is true.
309 * @param lockingEnabled set to true to enable locks, false otherwise
310 */
311 public void setLockingEnabled(boolean lockingEnabled) {
312 mLockingEnabled = lockingEnabled;
313 }
314
315 /**
316 * If set then the SQLiteDatabase is made thread-safe by using locks
317 * around critical sections
318 */
319 private boolean mLockingEnabled = true;
320
321 /* package */ void onCorruption() {
322 try {
323 // Close the database (if we can), which will cause subsequent operations to fail.
324 close();
325 } finally {
326 Log.e(TAG, "Removing corrupt database: " + mPath);
Vasu Noridd1b39b2010-01-08 10:11:24 -0800327 EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 // Delete the corrupt file. Don't re-create it now -- that would just confuse people
329 // -- but the next time someone tries to open it, they can set it up from scratch.
330 new File(mPath).delete();
331 }
332 }
333
334 /**
335 * Locks the database for exclusive access. The database lock must be held when
336 * touch the native sqlite3* object since it is single threaded and uses
337 * a polling lock contention algorithm. The lock is recursive, and may be acquired
338 * multiple times by the same thread. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700339 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 * @see #unlock()
341 */
342 /* package */ void lock() {
343 if (!mLockingEnabled) return;
344 mLock.lock();
345 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
346 if (mLock.getHoldCount() == 1) {
347 // Use elapsed real-time since the CPU may sleep when waiting for IO
348 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
349 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
350 }
351 }
352 }
353
354 /**
355 * Locks the database for exclusive access. The database lock must be held when
356 * touch the native sqlite3* object since it is single threaded and uses
357 * a polling lock contention algorithm. The lock is recursive, and may be acquired
358 * multiple times by the same thread.
359 *
360 * @see #unlockForced()
361 */
362 private void lockForced() {
363 mLock.lock();
364 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
365 if (mLock.getHoldCount() == 1) {
366 // Use elapsed real-time since the CPU may sleep when waiting for IO
367 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
368 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
369 }
370 }
371 }
372
373 /**
374 * Releases the database lock. This is a no-op if mLockingEnabled is false.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700375 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 * @see #unlock()
377 */
378 /* package */ void unlock() {
379 if (!mLockingEnabled) return;
380 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
381 if (mLock.getHoldCount() == 1) {
382 checkLockHoldTime();
383 }
384 }
385 mLock.unlock();
386 }
387
388 /**
389 * Releases the database lock.
390 *
391 * @see #unlockForced()
392 */
393 private void unlockForced() {
394 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING) {
395 if (mLock.getHoldCount() == 1) {
396 checkLockHoldTime();
397 }
398 }
399 mLock.unlock();
400 }
401
402 private void checkLockHoldTime() {
403 // Use elapsed real-time since the CPU may sleep when waiting for IO
404 long elapsedTime = SystemClock.elapsedRealtime();
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700405 long lockedTime = elapsedTime - mLockAcquiredWallTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 if (lockedTime < LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT &&
407 !Log.isLoggable(TAG, Log.VERBOSE) &&
408 (elapsedTime - mLastLockMessageTime) < LOCK_WARNING_WINDOW_IN_MS) {
409 return;
410 }
411 if (lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS) {
412 int threadTime = (int)
413 ((Debug.threadCpuTimeNanos() - mLockAcquiredThreadTime) / 1000000);
414 if (threadTime > LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS ||
415 lockedTime > LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT) {
416 mLastLockMessageTime = elapsedTime;
417 String msg = "lock held on " + mPath + " for " + lockedTime + "ms. Thread time was "
418 + threadTime + "ms";
419 if (SQLiteDebug.DEBUG_LOCK_TIME_TRACKING_STACK_TRACE) {
420 Log.d(TAG, msg, new Exception());
421 } else {
422 Log.d(TAG, msg);
423 }
424 }
425 }
426 }
427
428 /**
429 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
430 * the work done in that transaction and all of the nested transactions will be committed or
431 * rolled back. The changes will be rolled back if any transaction is ended without being
432 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
433 *
434 * <p>Here is the standard idiom for transactions:
435 *
436 * <pre>
437 * db.beginTransaction();
438 * try {
439 * ...
440 * db.setTransactionSuccessful();
441 * } finally {
442 * db.endTransaction();
443 * }
444 * </pre>
445 */
446 public void beginTransaction() {
Fred Quintanac4516a72009-09-03 12:14:06 -0700447 beginTransactionWithListener(null /* transactionStatusCallback */);
448 }
449
450 /**
451 * Begins a transaction. Transactions can be nested. When the outer transaction is ended all of
452 * the work done in that transaction and all of the nested transactions will be committed or
453 * rolled back. The changes will be rolled back if any transaction is ended without being
454 * marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
455 *
456 * <p>Here is the standard idiom for transactions:
457 *
458 * <pre>
459 * db.beginTransactionWithListener(listener);
460 * try {
461 * ...
462 * db.setTransactionSuccessful();
463 * } finally {
464 * db.endTransaction();
465 * }
466 * </pre>
467 * @param transactionListener listener that should be notified when the transaction begins,
468 * commits, or is rolled back, either explicitly or by a call to
469 * {@link #yieldIfContendedSafely}.
470 */
471 public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 lockForced();
473 boolean ok = false;
474 try {
475 // If this thread already had the lock then get out
476 if (mLock.getHoldCount() > 1) {
477 if (mInnerTransactionIsSuccessful) {
478 String msg = "Cannot call beginTransaction between "
479 + "calling setTransactionSuccessful and endTransaction";
480 IllegalStateException e = new IllegalStateException(msg);
481 Log.e(TAG, "beginTransaction() failed", e);
482 throw e;
483 }
484 ok = true;
485 return;
486 }
487
488 // This thread didn't already have the lock, so begin a database
489 // transaction now.
490 execSQL("BEGIN EXCLUSIVE;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700491 mTransactionListener = transactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 mTransactionIsSuccessful = true;
493 mInnerTransactionIsSuccessful = false;
Fred Quintanac4516a72009-09-03 12:14:06 -0700494 if (transactionListener != null) {
495 try {
496 transactionListener.onBegin();
497 } catch (RuntimeException e) {
498 execSQL("ROLLBACK;");
499 throw e;
500 }
501 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 ok = true;
503 } finally {
504 if (!ok) {
505 // beginTransaction is called before the try block so we must release the lock in
506 // the case of failure.
507 unlockForced();
508 }
509 }
510 }
511
512 /**
513 * End a transaction. See beginTransaction for notes about how to use this and when transactions
514 * are committed and rolled back.
515 */
516 public void endTransaction() {
517 if (!mLock.isHeldByCurrentThread()) {
518 throw new IllegalStateException("no transaction pending");
519 }
520 try {
521 if (mInnerTransactionIsSuccessful) {
522 mInnerTransactionIsSuccessful = false;
523 } else {
524 mTransactionIsSuccessful = false;
525 }
526 if (mLock.getHoldCount() != 1) {
527 return;
528 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700529 RuntimeException savedException = null;
530 if (mTransactionListener != null) {
531 try {
532 if (mTransactionIsSuccessful) {
533 mTransactionListener.onCommit();
534 } else {
535 mTransactionListener.onRollback();
536 }
537 } catch (RuntimeException e) {
538 savedException = e;
539 mTransactionIsSuccessful = false;
540 }
541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 if (mTransactionIsSuccessful) {
543 execSQL("COMMIT;");
544 } else {
545 try {
546 execSQL("ROLLBACK;");
Fred Quintanac4516a72009-09-03 12:14:06 -0700547 if (savedException != null) {
548 throw savedException;
549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 } catch (SQLException e) {
551 if (Config.LOGD) {
552 Log.d(TAG, "exception during rollback, maybe the DB previously "
553 + "performed an auto-rollback");
554 }
555 }
556 }
557 } finally {
Fred Quintanac4516a72009-09-03 12:14:06 -0700558 mTransactionListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 unlockForced();
560 if (Config.LOGV) {
561 Log.v(TAG, "unlocked " + Thread.currentThread()
562 + ", holdCount is " + mLock.getHoldCount());
563 }
564 }
565 }
566
567 /**
568 * Marks the current transaction as successful. Do not do any more database work between
569 * calling this and calling endTransaction. Do as little non-database work as possible in that
570 * situation too. If any errors are encountered between this and endTransaction the transaction
571 * will still be committed.
572 *
573 * @throws IllegalStateException if the current thread is not in a transaction or the
574 * transaction is already marked as successful.
575 */
576 public void setTransactionSuccessful() {
577 if (!mLock.isHeldByCurrentThread()) {
578 throw new IllegalStateException("no transaction pending");
579 }
580 if (mInnerTransactionIsSuccessful) {
581 throw new IllegalStateException(
582 "setTransactionSuccessful may only be called once per call to beginTransaction");
583 }
584 mInnerTransactionIsSuccessful = true;
585 }
586
587 /**
588 * return true if there is a transaction pending
589 */
590 public boolean inTransaction() {
591 return mLock.getHoldCount() > 0;
592 }
593
594 /**
595 * Checks if the database lock is held by this thread.
596 *
597 * @return true, if this thread is holding the database lock.
598 */
599 public boolean isDbLockedByCurrentThread() {
600 return mLock.isHeldByCurrentThread();
601 }
602
603 /**
604 * Checks if the database is locked by another thread. This is
605 * just an estimate, since this status can change at any time,
606 * including after the call is made but before the result has
607 * been acted upon.
608 *
609 * @return true, if the database is locked by another thread
610 */
611 public boolean isDbLockedByOtherThreads() {
612 return !mLock.isHeldByCurrentThread() && mLock.isLocked();
613 }
614
615 /**
616 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
617 * successful so far. Do not call setTransactionSuccessful before calling this. When this
618 * returns a new transaction will have been created but not marked as successful.
619 * @return true if the transaction was yielded
620 * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
621 * will not be yielded. Use yieldIfContendedSafely instead.
622 */
Dianne Hackborn4a51c202009-08-21 15:14:02 -0700623 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 public boolean yieldIfContended() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700625 return yieldIfContendedHelper(false /* do not check yielding */,
626 -1 /* sleepAfterYieldDelay */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 }
628
629 /**
630 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
631 * successful so far. Do not call setTransactionSuccessful before calling this. When this
632 * returns a new transaction will have been created but not marked as successful. This assumes
633 * that there are no nested transactions (beginTransaction has only been called once) and will
Fred Quintana5c7aede2009-08-27 21:41:27 -0700634 * throw an exception if that is not the case.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 * @return true if the transaction was yielded
636 */
637 public boolean yieldIfContendedSafely() {
Fred Quintana5c7aede2009-08-27 21:41:27 -0700638 return yieldIfContendedHelper(true /* check yielding */, -1 /* sleepAfterYieldDelay*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 }
640
Fred Quintana5c7aede2009-08-27 21:41:27 -0700641 /**
642 * Temporarily end the transaction to let other threads run. The transaction is assumed to be
643 * successful so far. Do not call setTransactionSuccessful before calling this. When this
644 * returns a new transaction will have been created but not marked as successful. This assumes
645 * that there are no nested transactions (beginTransaction has only been called once) and will
646 * throw an exception if that is not the case.
647 * @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
648 * the lock was actually yielded. This will allow other background threads to make some
649 * more progress than they would if we started the transaction immediately.
650 * @return true if the transaction was yielded
651 */
652 public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
653 return yieldIfContendedHelper(true /* check yielding */, sleepAfterYieldDelay);
654 }
655
656 private boolean yieldIfContendedHelper(boolean checkFullyYielded, long sleepAfterYieldDelay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 if (mLock.getQueueLength() == 0) {
658 // Reset the lock acquire time since we know that the thread was willing to yield
659 // the lock at this time.
660 mLockAcquiredWallTime = SystemClock.elapsedRealtime();
661 mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
662 return false;
663 }
664 setTransactionSuccessful();
Fred Quintanac4516a72009-09-03 12:14:06 -0700665 SQLiteTransactionListener transactionListener = mTransactionListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 endTransaction();
667 if (checkFullyYielded) {
668 if (this.isDbLockedByCurrentThread()) {
669 throw new IllegalStateException(
670 "Db locked more than once. yielfIfContended cannot yield");
671 }
672 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700673 if (sleepAfterYieldDelay > 0) {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700674 // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
675 // check if anyone is using the database. If the database is not contended,
676 // retake the lock and return.
677 long remainingDelay = sleepAfterYieldDelay;
678 while (remainingDelay > 0) {
679 try {
680 Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
681 remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
682 } catch (InterruptedException e) {
683 Thread.interrupted();
684 }
685 remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
686 if (mLock.getQueueLength() == 0) {
687 break;
688 }
Fred Quintana5c7aede2009-08-27 21:41:27 -0700689 }
690 }
Fred Quintanac4516a72009-09-03 12:14:06 -0700691 beginTransactionWithListener(transactionListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 return true;
693 }
694
695 /** Maps table names to info about what to which _sync_time column to set
696 * to NULL on an update. This is used to support syncing. */
697 private final Map<String, SyncUpdateInfo> mSyncUpdateInfo =
698 new HashMap<String, SyncUpdateInfo>();
699
700 public Map<String, String> getSyncedTables() {
701 synchronized(mSyncUpdateInfo) {
702 HashMap<String, String> tables = new HashMap<String, String>();
703 for (String table : mSyncUpdateInfo.keySet()) {
704 SyncUpdateInfo info = mSyncUpdateInfo.get(table);
705 if (info.deletedTable != null) {
706 tables.put(table, info.deletedTable);
707 }
708 }
709 return tables;
710 }
711 }
712
713 /**
714 * Internal class used to keep track what needs to be marked as changed
715 * when an update occurs. This is used for syncing, so the sync engine
716 * knows what data has been updated locally.
717 */
718 static private class SyncUpdateInfo {
719 /**
720 * Creates the SyncUpdateInfo class.
721 *
722 * @param masterTable The table to set _sync_time to NULL in
723 * @param deletedTable The deleted table that corresponds to the
724 * master table
725 * @param foreignKey The key that refers to the primary key in table
726 */
727 SyncUpdateInfo(String masterTable, String deletedTable,
728 String foreignKey) {
729 this.masterTable = masterTable;
730 this.deletedTable = deletedTable;
731 this.foreignKey = foreignKey;
732 }
733
734 /** The table containing the _sync_time column */
735 String masterTable;
736
737 /** The deleted table that corresponds to the master table */
738 String deletedTable;
739
740 /** The key in the local table the row in table. It may be _id, if table
741 * is the local table. */
742 String foreignKey;
743 }
744
745 /**
746 * Used to allow returning sub-classes of {@link Cursor} when calling query.
747 */
748 public interface CursorFactory {
749 /**
750 * See
751 * {@link SQLiteCursor#SQLiteCursor(SQLiteDatabase, SQLiteCursorDriver,
752 * String, SQLiteQuery)}.
753 */
754 public Cursor newCursor(SQLiteDatabase db,
755 SQLiteCursorDriver masterQuery, String editTable,
756 SQLiteQuery query);
757 }
758
759 /**
760 * Open the database according to the flags {@link #OPEN_READWRITE}
761 * {@link #OPEN_READONLY} {@link #CREATE_IF_NECESSARY} and/or {@link #NO_LOCALIZED_COLLATORS}.
762 *
763 * <p>Sets the locale of the database to the the system's current locale.
764 * Call {@link #setLocale} if you would like something else.</p>
765 *
766 * @param path to database file to open and/or create
767 * @param factory an optional factory class that is called to instantiate a
768 * cursor when query is called, or null for default
769 * @param flags to control database access mode
770 * @return the newly opened database
771 * @throws SQLiteException if the database cannot be opened
772 */
773 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
774 SQLiteDatabase db = null;
775 try {
776 // Open the database.
Vasu Nori3ef94e22010-02-05 14:49:04 -0800777 SQLiteDatabase sqliteDatabase = new SQLiteDatabase(path, factory, flags);
778 if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
779 sqliteDatabase.enableSqlTracing(path);
780 }
781 if (SQLiteDebug.DEBUG_SQL_TIME) {
782 sqliteDatabase.enableSqlProfiling(path);
783 }
784 return sqliteDatabase;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 } catch (SQLiteDatabaseCorruptException e) {
786 // Try to recover from this, if we can.
787 // TODO: should we do this for other open failures?
788 Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
Jeff Hamilton082c2af2009-09-29 11:49:51 -0700789 EventLog.writeEvent(EVENT_DB_CORRUPT, path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 new File(path).delete();
791 return new SQLiteDatabase(path, factory, flags);
792 }
793 }
794
795 /**
796 * Equivalent to openDatabase(file.getPath(), factory, CREATE_IF_NECESSARY).
797 */
798 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
799 return openOrCreateDatabase(file.getPath(), factory);
800 }
801
802 /**
803 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
804 */
805 public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
806 return openDatabase(path, factory, CREATE_IF_NECESSARY);
807 }
808
809 /**
810 * Create a memory backed SQLite database. Its contents will be destroyed
811 * when the database is closed.
812 *
813 * <p>Sets the locale of the database to the the system's current locale.
814 * Call {@link #setLocale} if you would like something else.</p>
815 *
816 * @param factory an optional factory class that is called to instantiate a
817 * cursor when query is called
818 * @return a SQLiteDatabase object, or null if the database can't be created
819 */
820 public static SQLiteDatabase create(CursorFactory factory) {
821 // This is a magic string with special meaning for SQLite.
822 return openDatabase(":memory:", factory, CREATE_IF_NECESSARY);
823 }
824
825 /**
826 * Close the database.
827 */
828 public void close() {
829 lock();
830 try {
831 closeClosable();
832 releaseReference();
833 } finally {
834 unlock();
835 }
836 }
837
838 private void closeClosable() {
Vasu Norie495d1f2010-01-06 16:34:19 -0800839 /* deallocate all compiled sql statement objects from mCompiledQueries cache.
840 * this should be done before de-referencing all {@link SQLiteClosable} objects
841 * from this database object because calling
842 * {@link SQLiteClosable#onAllReferencesReleasedFromContainer()} could cause the database
843 * to be closed. sqlite doesn't let a database close if there are
844 * any unfinalized statements - such as the compiled-sql objects in mCompiledQueries.
845 */
846 deallocCachedSqlStatements();
847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
849 while (iter.hasNext()) {
850 Map.Entry<SQLiteClosable, Object> entry = iter.next();
851 SQLiteClosable program = entry.getKey();
852 if (program != null) {
853 program.onAllReferencesReleasedFromContainer();
854 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -0700857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 /**
859 * Native call to close the database.
860 */
861 private native void dbclose();
862
863 /**
864 * Gets the database version.
865 *
866 * @return the database version
867 */
868 public int getVersion() {
869 SQLiteStatement prog = null;
870 lock();
871 try {
872 prog = new SQLiteStatement(this, "PRAGMA user_version;");
873 long version = prog.simpleQueryForLong();
874 return (int) version;
875 } finally {
876 if (prog != null) prog.close();
877 unlock();
878 }
879 }
880
881 /**
882 * Sets the database version.
883 *
884 * @param version the new database version
885 */
886 public void setVersion(int version) {
887 execSQL("PRAGMA user_version = " + version);
888 }
889
890 /**
891 * Returns the maximum size the database may grow to.
892 *
893 * @return the new maximum database size
894 */
895 public long getMaximumSize() {
896 SQLiteStatement prog = null;
897 lock();
898 try {
899 prog = new SQLiteStatement(this,
900 "PRAGMA max_page_count;");
901 long pageCount = prog.simpleQueryForLong();
902 return pageCount * getPageSize();
903 } finally {
904 if (prog != null) prog.close();
905 unlock();
906 }
907 }
908
909 /**
910 * Sets the maximum size the database will grow to. The maximum size cannot
911 * be set below the current size.
912 *
913 * @param numBytes the maximum database size, in bytes
914 * @return the new maximum database size
915 */
916 public long setMaximumSize(long numBytes) {
917 SQLiteStatement prog = null;
918 lock();
919 try {
920 long pageSize = getPageSize();
921 long numPages = numBytes / pageSize;
922 // If numBytes isn't a multiple of pageSize, bump up a page
923 if ((numBytes % pageSize) != 0) {
924 numPages++;
925 }
926 prog = new SQLiteStatement(this,
927 "PRAGMA max_page_count = " + numPages);
928 long newPageCount = prog.simpleQueryForLong();
929 return newPageCount * pageSize;
930 } finally {
931 if (prog != null) prog.close();
932 unlock();
933 }
934 }
935
936 /**
937 * Returns the current database page size, in bytes.
938 *
939 * @return the database page size, in bytes
940 */
941 public long getPageSize() {
942 SQLiteStatement prog = null;
943 lock();
944 try {
945 prog = new SQLiteStatement(this,
946 "PRAGMA page_size;");
947 long size = prog.simpleQueryForLong();
948 return size;
949 } finally {
950 if (prog != null) prog.close();
951 unlock();
952 }
953 }
954
955 /**
956 * Sets the database page size. The page size must be a power of two. This
957 * method does not work if any data has been written to the database file,
958 * and must be called right after the database has been created.
959 *
960 * @param numBytes the database page size, in bytes
961 */
962 public void setPageSize(long numBytes) {
963 execSQL("PRAGMA page_size = " + numBytes);
964 }
965
966 /**
967 * Mark this table as syncable. When an update occurs in this table the
968 * _sync_dirty field will be set to ensure proper syncing operation.
969 *
970 * @param table the table to mark as syncable
971 * @param deletedTable The deleted table that corresponds to the
972 * syncable table
973 */
974 public void markTableSyncable(String table, String deletedTable) {
975 markTableSyncable(table, "_id", table, deletedTable);
976 }
977
978 /**
979 * Mark this table as syncable, with the _sync_dirty residing in another
980 * table. When an update occurs in this table the _sync_dirty field of the
981 * row in updateTable with the _id in foreignKey will be set to
982 * ensure proper syncing operation.
983 *
984 * @param table an update on this table will trigger a sync time removal
985 * @param foreignKey this is the column in table whose value is an _id in
986 * updateTable
987 * @param updateTable this is the table that will have its _sync_dirty
988 */
989 public void markTableSyncable(String table, String foreignKey,
990 String updateTable) {
991 markTableSyncable(table, foreignKey, updateTable, null);
992 }
993
994 /**
995 * Mark this table as syncable, with the _sync_dirty residing in another
996 * table. When an update occurs in this table the _sync_dirty field of the
997 * row in updateTable with the _id in foreignKey will be set to
998 * ensure proper syncing operation.
999 *
1000 * @param table an update on this table will trigger a sync time removal
1001 * @param foreignKey this is the column in table whose value is an _id in
1002 * updateTable
1003 * @param updateTable this is the table that will have its _sync_dirty
1004 * @param deletedTable The deleted table that corresponds to the
1005 * updateTable
1006 */
1007 private void markTableSyncable(String table, String foreignKey,
1008 String updateTable, String deletedTable) {
1009 lock();
1010 try {
1011 native_execSQL("SELECT _sync_dirty FROM " + updateTable
1012 + " LIMIT 0");
1013 native_execSQL("SELECT " + foreignKey + " FROM " + table
1014 + " LIMIT 0");
1015 } finally {
1016 unlock();
1017 }
1018
1019 SyncUpdateInfo info = new SyncUpdateInfo(updateTable, deletedTable,
1020 foreignKey);
1021 synchronized (mSyncUpdateInfo) {
1022 mSyncUpdateInfo.put(table, info);
1023 }
1024 }
1025
1026 /**
1027 * Call for each row that is updated in a cursor.
1028 *
1029 * @param table the table the row is in
1030 * @param rowId the row ID of the updated row
1031 */
1032 /* package */ void rowUpdated(String table, long rowId) {
1033 SyncUpdateInfo info;
1034 synchronized (mSyncUpdateInfo) {
1035 info = mSyncUpdateInfo.get(table);
1036 }
1037 if (info != null) {
1038 execSQL("UPDATE " + info.masterTable
1039 + " SET _sync_dirty=1 WHERE _id=(SELECT " + info.foreignKey
1040 + " FROM " + table + " WHERE _id=" + rowId + ")");
1041 }
1042 }
1043
1044 /**
1045 * Finds the name of the first table, which is editable.
1046 *
1047 * @param tables a list of tables
1048 * @return the first table listed
1049 */
1050 public static String findEditTable(String tables) {
1051 if (!TextUtils.isEmpty(tables)) {
1052 // find the first word terminated by either a space or a comma
1053 int spacepos = tables.indexOf(' ');
1054 int commapos = tables.indexOf(',');
1055
1056 if (spacepos > 0 && (spacepos < commapos || commapos < 0)) {
1057 return tables.substring(0, spacepos);
1058 } else if (commapos > 0 && (commapos < spacepos || spacepos < 0) ) {
1059 return tables.substring(0, commapos);
1060 }
1061 return tables;
1062 } else {
1063 throw new IllegalStateException("Invalid tables");
1064 }
1065 }
1066
1067 /**
1068 * Compiles an SQL statement into a reusable pre-compiled statement object.
1069 * The parameters are identical to {@link #execSQL(String)}. You may put ?s in the
1070 * statement and fill in those values with {@link SQLiteProgram#bindString}
1071 * and {@link SQLiteProgram#bindLong} each time you want to run the
1072 * statement. Statements may not return result sets larger than 1x1.
1073 *
1074 * @param sql The raw SQL statement, may contain ? for unknown values to be
1075 * bound later.
1076 * @return a pre-compiled statement object.
1077 */
1078 public SQLiteStatement compileStatement(String sql) throws SQLException {
1079 lock();
1080 try {
1081 return new SQLiteStatement(this, sql);
1082 } finally {
1083 unlock();
1084 }
1085 }
1086
1087 /**
1088 * Query the given URL, returning a {@link Cursor} over the result set.
1089 *
1090 * @param distinct true if you want each row to be unique, false otherwise.
1091 * @param table The table name to compile the query against.
1092 * @param columns A list of which columns to return. Passing null will
1093 * return all columns, which is discouraged to prevent reading
1094 * data from storage that isn't going to be used.
1095 * @param selection A filter declaring which rows to return, formatted as an
1096 * SQL WHERE clause (excluding the WHERE itself). Passing null
1097 * will return all rows for the given table.
1098 * @param selectionArgs You may include ?s in selection, which will be
1099 * replaced by the values from selectionArgs, in order that they
1100 * appear in the selection. The values will be bound as Strings.
1101 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1102 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1103 * will cause the rows to not be grouped.
1104 * @param having A filter declare which row groups to include in the cursor,
1105 * if row grouping is being used, formatted as an SQL HAVING
1106 * clause (excluding the HAVING itself). Passing null will cause
1107 * all row groups to be included, and is required when row
1108 * grouping is not being used.
1109 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1110 * (excluding the ORDER BY itself). Passing null will use the
1111 * default sort order, which may be unordered.
1112 * @param limit Limits the number of rows returned by the query,
1113 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1114 * @return A Cursor object, which is positioned before the first entry
1115 * @see Cursor
1116 */
1117 public Cursor query(boolean distinct, String table, String[] columns,
1118 String selection, String[] selectionArgs, String groupBy,
1119 String having, String orderBy, String limit) {
1120 return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
1121 groupBy, having, orderBy, limit);
1122 }
1123
1124 /**
1125 * Query the given URL, returning a {@link Cursor} over the result set.
1126 *
1127 * @param cursorFactory the cursor factory to use, or null for the default factory
1128 * @param distinct true if you want each row to be unique, false otherwise.
1129 * @param table The table name to compile the query against.
1130 * @param columns A list of which columns to return. Passing null will
1131 * return all columns, which is discouraged to prevent reading
1132 * data from storage that isn't going to be used.
1133 * @param selection A filter declaring which rows to return, formatted as an
1134 * SQL WHERE clause (excluding the WHERE itself). Passing null
1135 * will return all rows for the given table.
1136 * @param selectionArgs You may include ?s in selection, which will be
1137 * replaced by the values from selectionArgs, in order that they
1138 * appear in the selection. The values will be bound as Strings.
1139 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1140 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1141 * will cause the rows to not be grouped.
1142 * @param having A filter declare which row groups to include in the cursor,
1143 * if row grouping is being used, formatted as an SQL HAVING
1144 * clause (excluding the HAVING itself). Passing null will cause
1145 * all row groups to be included, and is required when row
1146 * grouping is not being used.
1147 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1148 * (excluding the ORDER BY itself). Passing null will use the
1149 * default sort order, which may be unordered.
1150 * @param limit Limits the number of rows returned by the query,
1151 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1152 * @return A Cursor object, which is positioned before the first entry
1153 * @see Cursor
1154 */
1155 public Cursor queryWithFactory(CursorFactory cursorFactory,
1156 boolean distinct, String table, String[] columns,
1157 String selection, String[] selectionArgs, String groupBy,
1158 String having, String orderBy, String limit) {
1159 String sql = SQLiteQueryBuilder.buildQueryString(
1160 distinct, table, columns, selection, groupBy, having, orderBy, limit);
1161
1162 return rawQueryWithFactory(
1163 cursorFactory, sql, selectionArgs, findEditTable(table));
1164 }
1165
1166 /**
1167 * Query the given table, returning a {@link Cursor} over the result set.
1168 *
1169 * @param table The table name to compile the query against.
1170 * @param columns A list of which columns to return. Passing null will
1171 * return all columns, which is discouraged to prevent reading
1172 * data from storage that isn't going to be used.
1173 * @param selection A filter declaring which rows to return, formatted as an
1174 * SQL WHERE clause (excluding the WHERE itself). Passing null
1175 * will return all rows for the given table.
1176 * @param selectionArgs You may include ?s in selection, which will be
1177 * replaced by the values from selectionArgs, in order that they
1178 * appear in the selection. The values will be bound as Strings.
1179 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1180 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1181 * will cause the rows to not be grouped.
1182 * @param having A filter declare which row groups to include in the cursor,
1183 * if row grouping is being used, formatted as an SQL HAVING
1184 * clause (excluding the HAVING itself). Passing null will cause
1185 * all row groups to be included, and is required when row
1186 * grouping is not being used.
1187 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1188 * (excluding the ORDER BY itself). Passing null will use the
1189 * default sort order, which may be unordered.
1190 * @return A {@link Cursor} object, which is positioned before the first entry
1191 * @see Cursor
1192 */
1193 public Cursor query(String table, String[] columns, String selection,
1194 String[] selectionArgs, String groupBy, String having,
1195 String orderBy) {
1196
1197 return query(false, table, columns, selection, selectionArgs, groupBy,
1198 having, orderBy, null /* limit */);
1199 }
1200
1201 /**
1202 * Query the given table, returning a {@link Cursor} over the result set.
1203 *
1204 * @param table The table name to compile the query against.
1205 * @param columns A list of which columns to return. Passing null will
1206 * return all columns, which is discouraged to prevent reading
1207 * data from storage that isn't going to be used.
1208 * @param selection A filter declaring which rows to return, formatted as an
1209 * SQL WHERE clause (excluding the WHERE itself). Passing null
1210 * will return all rows for the given table.
1211 * @param selectionArgs You may include ?s in selection, which will be
1212 * replaced by the values from selectionArgs, in order that they
1213 * appear in the selection. The values will be bound as Strings.
1214 * @param groupBy A filter declaring how to group rows, formatted as an SQL
1215 * GROUP BY clause (excluding the GROUP BY itself). Passing null
1216 * will cause the rows to not be grouped.
1217 * @param having A filter declare which row groups to include in the cursor,
1218 * if row grouping is being used, formatted as an SQL HAVING
1219 * clause (excluding the HAVING itself). Passing null will cause
1220 * all row groups to be included, and is required when row
1221 * grouping is not being used.
1222 * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
1223 * (excluding the ORDER BY itself). Passing null will use the
1224 * default sort order, which may be unordered.
1225 * @param limit Limits the number of rows returned by the query,
1226 * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
1227 * @return A {@link Cursor} object, which is positioned before the first entry
1228 * @see Cursor
1229 */
1230 public Cursor query(String table, String[] columns, String selection,
1231 String[] selectionArgs, String groupBy, String having,
1232 String orderBy, String limit) {
1233
1234 return query(false, table, columns, selection, selectionArgs, groupBy,
1235 having, orderBy, limit);
1236 }
1237
1238 /**
1239 * Runs the provided SQL and returns a {@link Cursor} over the result set.
1240 *
1241 * @param sql the SQL query. The SQL string must not be ; terminated
1242 * @param selectionArgs You may include ?s in where clause in the query,
1243 * which will be replaced by the values from selectionArgs. The
1244 * values will be bound as Strings.
1245 * @return A {@link Cursor} object, which is positioned before the first entry
1246 */
1247 public Cursor rawQuery(String sql, String[] selectionArgs) {
1248 return rawQueryWithFactory(null, sql, selectionArgs, null);
1249 }
1250
1251 /**
1252 * Runs the provided SQL and returns a cursor over the result set.
1253 *
1254 * @param cursorFactory the cursor factory to use, or null for the default factory
1255 * @param sql the SQL query. The SQL string must not be ; terminated
1256 * @param selectionArgs You may include ?s in where clause in the query,
1257 * which will be replaced by the values from selectionArgs. The
1258 * values will be bound as Strings.
1259 * @param editTable the name of the first table, which is editable
1260 * @return A {@link Cursor} object, which is positioned before the first entry
1261 */
1262 public Cursor rawQueryWithFactory(
1263 CursorFactory cursorFactory, String sql, String[] selectionArgs,
1264 String editTable) {
1265 long timeStart = 0;
1266
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001267 if (Config.LOGV || mSlowQueryThreshold != -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 timeStart = System.currentTimeMillis();
1269 }
1270
1271 SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
1272
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001273 Cursor cursor = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 try {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001275 cursor = driver.query(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 cursorFactory != null ? cursorFactory : mFactory,
1277 selectionArgs);
1278 } finally {
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001279 if (Config.LOGV || mSlowQueryThreshold != -1) {
1280
1281 // Force query execution
1282 if (cursor != null) {
1283 cursor.moveToFirst();
1284 cursor.moveToPosition(-1);
1285 }
1286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 long duration = System.currentTimeMillis() - timeStart;
1288
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001289 if (Config.LOGV || duration >= mSlowQueryThreshold) {
1290 Log.v(SQLiteCursor.TAG,
1291 "query (" + duration + " ms): " + driver.toString() + ", args are "
1292 + (selectionArgs != null
1293 ? TextUtils.join(",", selectionArgs)
1294 : "<null>"));
1295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 }
1297 }
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001298 return cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 }
1300
1301 /**
1302 * Runs the provided SQL and returns a cursor over the result set.
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001303 * The cursor will read an initial set of rows and the return to the caller.
1304 * It will continue to read in batches and send data changed notifications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 * when the later batches are ready.
1306 * @param sql the SQL query. The SQL string must not be ; terminated
1307 * @param selectionArgs You may include ?s in where clause in the query,
1308 * which will be replaced by the values from selectionArgs. The
1309 * values will be bound as Strings.
1310 * @param initialRead set the initial count of items to read from the cursor
1311 * @param maxRead set the count of items to read on each iteration after the first
1312 * @return A {@link Cursor} object, which is positioned before the first entry
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001313 *
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001314 * This work is incomplete and not fully tested or reviewed, so currently
1315 * hidden.
1316 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001318 public Cursor rawQuery(String sql, String[] selectionArgs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 int initialRead, int maxRead) {
1320 SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
1321 null, sql, selectionArgs, null);
1322 c.setLoadStyle(initialRead, maxRead);
1323 return c;
1324 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 /**
1327 * Convenience method for inserting a row into the database.
1328 *
1329 * @param table the table to insert the row into
1330 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1331 * so if initialValues is empty this column will explicitly be
1332 * assigned a NULL value
1333 * @param values this map contains the initial column values for the
1334 * row. The keys should be the column names and the values the
1335 * column values
1336 * @return the row ID of the newly inserted row, or -1 if an error occurred
1337 */
1338 public long insert(String table, String nullColumnHack, ContentValues values) {
1339 try {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001340 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 } catch (SQLException e) {
1342 Log.e(TAG, "Error inserting " + values, e);
1343 return -1;
1344 }
1345 }
1346
1347 /**
1348 * Convenience method for inserting a row into the database.
1349 *
1350 * @param table the table to insert the row into
1351 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1352 * so if initialValues is empty this column will explicitly be
1353 * assigned a NULL value
1354 * @param values this map contains the initial column values for the
1355 * row. The keys should be the column names and the values the
1356 * column values
1357 * @throws SQLException
1358 * @return the row ID of the newly inserted row, or -1 if an error occurred
1359 */
1360 public long insertOrThrow(String table, String nullColumnHack, ContentValues values)
1361 throws SQLException {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001362 return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 }
1364
1365 /**
1366 * Convenience method for replacing a row in the database.
1367 *
1368 * @param table the table in which to replace the row
1369 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1370 * so if initialValues is empty this row will explicitly be
1371 * assigned a NULL value
1372 * @param initialValues this map contains the initial column values for
1373 * the row. The key
1374 * @return the row ID of the newly inserted row, or -1 if an error occurred
1375 */
1376 public long replace(String table, String nullColumnHack, ContentValues initialValues) {
1377 try {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001378 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001379 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 } catch (SQLException e) {
1381 Log.e(TAG, "Error inserting " + initialValues, e);
1382 return -1;
1383 }
1384 }
1385
1386 /**
1387 * Convenience method for replacing a row in the database.
1388 *
1389 * @param table the table in which to replace the row
1390 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1391 * so if initialValues is empty this row will explicitly be
1392 * assigned a NULL value
1393 * @param initialValues this map contains the initial column values for
1394 * the row. The key
1395 * @throws SQLException
1396 * @return the row ID of the newly inserted row, or -1 if an error occurred
1397 */
1398 public long replaceOrThrow(String table, String nullColumnHack,
1399 ContentValues initialValues) throws SQLException {
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001400 return insertWithOnConflict(table, nullColumnHack, initialValues,
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001401 CONFLICT_REPLACE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 }
1403
1404 /**
1405 * General method for inserting a row into the database.
1406 *
1407 * @param table the table to insert the row into
1408 * @param nullColumnHack SQL doesn't allow inserting a completely empty row,
1409 * so if initialValues is empty this column will explicitly be
1410 * assigned a NULL value
1411 * @param initialValues this map contains the initial column values for the
1412 * row. The keys should be the column names and the values the
1413 * column values
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001414 * @param conflictAlgorithm for insert conflict resolver
Vasu Nori6eb7c452010-01-27 14:31:24 -08001415 * @return the row ID of the newly inserted row
1416 * OR the primary key of the existing row if the input param 'conflictAlgorithm' =
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001417 * {@link #CONFLICT_IGNORE}
Vasu Nori6eb7c452010-01-27 14:31:24 -08001418 * OR -1 if any error
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 */
1420 public long insertWithOnConflict(String table, String nullColumnHack,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001421 ContentValues initialValues, int conflictAlgorithm) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 if (!isOpen()) {
1423 throw new IllegalStateException("database not open");
1424 }
1425
1426 // Measurements show most sql lengths <= 152
1427 StringBuilder sql = new StringBuilder(152);
1428 sql.append("INSERT");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001429 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 sql.append(" INTO ");
1431 sql.append(table);
1432 // Measurements show most values lengths < 40
1433 StringBuilder values = new StringBuilder(40);
1434
1435 Set<Map.Entry<String, Object>> entrySet = null;
1436 if (initialValues != null && initialValues.size() > 0) {
1437 entrySet = initialValues.valueSet();
1438 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1439 sql.append('(');
1440
1441 boolean needSeparator = false;
1442 while (entriesIter.hasNext()) {
1443 if (needSeparator) {
1444 sql.append(", ");
1445 values.append(", ");
1446 }
1447 needSeparator = true;
1448 Map.Entry<String, Object> entry = entriesIter.next();
1449 sql.append(entry.getKey());
1450 values.append('?');
1451 }
1452
1453 sql.append(')');
1454 } else {
1455 sql.append("(" + nullColumnHack + ") ");
1456 values.append("NULL");
1457 }
1458
1459 sql.append(" VALUES(");
1460 sql.append(values);
1461 sql.append(");");
1462
1463 lock();
1464 SQLiteStatement statement = null;
1465 try {
1466 statement = compileStatement(sql.toString());
1467
1468 // Bind the values
1469 if (entrySet != null) {
1470 int size = entrySet.size();
1471 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1472 for (int i = 0; i < size; i++) {
1473 Map.Entry<String, Object> entry = entriesIter.next();
1474 DatabaseUtils.bindObjectToProgram(statement, i + 1, entry.getValue());
1475 }
1476 }
1477
1478 // Run the program and then cleanup
1479 statement.execute();
1480
1481 long insertedRowId = lastInsertRow();
1482 if (insertedRowId == -1) {
1483 Log.e(TAG, "Error inserting " + initialValues + " using " + sql);
1484 } else {
1485 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1486 Log.v(TAG, "Inserting row " + insertedRowId + " from "
1487 + initialValues + " using " + sql);
1488 }
1489 }
1490 return insertedRowId;
1491 } catch (SQLiteDatabaseCorruptException e) {
1492 onCorruption();
1493 throw e;
1494 } finally {
1495 if (statement != null) {
1496 statement.close();
1497 }
1498 unlock();
1499 }
1500 }
1501
1502 /**
1503 * Convenience method for deleting rows in the database.
1504 *
1505 * @param table the table to delete from
1506 * @param whereClause the optional WHERE clause to apply when deleting.
1507 * Passing null will delete all rows.
1508 * @return the number of rows affected if a whereClause is passed in, 0
1509 * otherwise. To remove all rows and get a count pass "1" as the
1510 * whereClause.
1511 */
1512 public int delete(String table, String whereClause, String[] whereArgs) {
1513 if (!isOpen()) {
1514 throw new IllegalStateException("database not open");
1515 }
1516 lock();
1517 SQLiteStatement statement = null;
1518 try {
1519 statement = compileStatement("DELETE FROM " + table
1520 + (!TextUtils.isEmpty(whereClause)
1521 ? " WHERE " + whereClause : ""));
1522 if (whereArgs != null) {
1523 int numArgs = whereArgs.length;
1524 for (int i = 0; i < numArgs; i++) {
1525 DatabaseUtils.bindObjectToProgram(statement, i + 1, whereArgs[i]);
1526 }
1527 }
1528 statement.execute();
1529 statement.close();
1530 return lastChangeCount();
1531 } catch (SQLiteDatabaseCorruptException e) {
1532 onCorruption();
1533 throw e;
1534 } finally {
1535 if (statement != null) {
1536 statement.close();
1537 }
1538 unlock();
1539 }
1540 }
1541
1542 /**
1543 * Convenience method for updating rows in the database.
1544 *
1545 * @param table the table to update in
1546 * @param values a map from column names to new column values. null is a
1547 * valid value that will be translated to NULL.
1548 * @param whereClause the optional WHERE clause to apply when updating.
1549 * Passing null will update all rows.
1550 * @return the number of rows affected
1551 */
1552 public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001553 return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 /**
1557 * Convenience method for updating rows in the database.
1558 *
1559 * @param table the table to update in
1560 * @param values a map from column names to new column values. null is a
1561 * valid value that will be translated to NULL.
1562 * @param whereClause the optional WHERE clause to apply when updating.
1563 * Passing null will update all rows.
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001564 * @param conflictAlgorithm for update conflict resolver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 * @return the number of rows affected
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 */
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001567 public int updateWithOnConflict(String table, ContentValues values,
Vasu Nori6eb7c452010-01-27 14:31:24 -08001568 String whereClause, String[] whereArgs, int conflictAlgorithm) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 if (!isOpen()) {
1570 throw new IllegalStateException("database not open");
1571 }
1572
1573 if (values == null || values.size() == 0) {
1574 throw new IllegalArgumentException("Empty values");
1575 }
1576
1577 StringBuilder sql = new StringBuilder(120);
1578 sql.append("UPDATE ");
Vasu Nori8d45e4e2010-02-05 22:35:47 -08001579 sql.append(CONFLICT_VALUES[conflictAlgorithm]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 sql.append(table);
1581 sql.append(" SET ");
1582
1583 Set<Map.Entry<String, Object>> entrySet = values.valueSet();
1584 Iterator<Map.Entry<String, Object>> entriesIter = entrySet.iterator();
1585
1586 while (entriesIter.hasNext()) {
1587 Map.Entry<String, Object> entry = entriesIter.next();
1588 sql.append(entry.getKey());
1589 sql.append("=?");
1590 if (entriesIter.hasNext()) {
1591 sql.append(", ");
1592 }
1593 }
1594
1595 if (!TextUtils.isEmpty(whereClause)) {
1596 sql.append(" WHERE ");
1597 sql.append(whereClause);
1598 }
1599
1600 lock();
1601 SQLiteStatement statement = null;
1602 try {
1603 statement = compileStatement(sql.toString());
1604
1605 // Bind the values
1606 int size = entrySet.size();
1607 entriesIter = entrySet.iterator();
1608 int bindArg = 1;
1609 for (int i = 0; i < size; i++) {
1610 Map.Entry<String, Object> entry = entriesIter.next();
1611 DatabaseUtils.bindObjectToProgram(statement, bindArg, entry.getValue());
1612 bindArg++;
1613 }
1614
1615 if (whereArgs != null) {
1616 size = whereArgs.length;
1617 for (int i = 0; i < size; i++) {
1618 statement.bindString(bindArg, whereArgs[i]);
1619 bindArg++;
1620 }
1621 }
1622
1623 // Run the program and then cleanup
1624 statement.execute();
1625 statement.close();
1626 int numChangedRows = lastChangeCount();
1627 if (Config.LOGD && Log.isLoggable(TAG, Log.VERBOSE)) {
1628 Log.v(TAG, "Updated " + numChangedRows + " using " + values + " and " + sql);
1629 }
1630 return numChangedRows;
1631 } catch (SQLiteDatabaseCorruptException e) {
1632 onCorruption();
1633 throw e;
1634 } catch (SQLException e) {
1635 Log.e(TAG, "Error updating " + values + " using " + sql);
1636 throw e;
1637 } finally {
1638 if (statement != null) {
1639 statement.close();
1640 }
1641 unlock();
1642 }
1643 }
1644
1645 /**
1646 * Execute a single SQL statement that is not a query. For example, CREATE
1647 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1648 * supported. it takes a write lock
1649 *
1650 * @throws SQLException If the SQL string is invalid for some reason
1651 */
1652 public void execSQL(String sql) throws SQLException {
Dan Egnor12311952009-11-23 14:47:45 -08001653 long timeStart = Debug.threadCpuTimeNanos();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 lock();
1655 try {
1656 native_execSQL(sql);
1657 } catch (SQLiteDatabaseCorruptException e) {
1658 onCorruption();
1659 throw e;
1660 } finally {
1661 unlock();
1662 }
Dan Egnor12311952009-11-23 14:47:45 -08001663 logTimeStat(sql, timeStart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
1665
1666 /**
1667 * Execute a single SQL statement that is not a query. For example, CREATE
1668 * TABLE, DELETE, INSERT, etc. Multiple statements separated by ;s are not
1669 * supported. it takes a write lock,
1670 *
1671 * @param sql
1672 * @param bindArgs only byte[], String, Long and Double are supported in bindArgs.
1673 * @throws SQLException If the SQL string is invalid for some reason
1674 */
1675 public void execSQL(String sql, Object[] bindArgs) throws SQLException {
1676 if (bindArgs == null) {
1677 throw new IllegalArgumentException("Empty bindArgs");
1678 }
Dan Egnor12311952009-11-23 14:47:45 -08001679 long timeStart = Debug.threadCpuTimeNanos();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 lock();
1681 SQLiteStatement statement = null;
1682 try {
1683 statement = compileStatement(sql);
1684 if (bindArgs != null) {
1685 int numArgs = bindArgs.length;
1686 for (int i = 0; i < numArgs; i++) {
1687 DatabaseUtils.bindObjectToProgram(statement, i + 1, bindArgs[i]);
1688 }
1689 }
1690 statement.execute();
1691 } catch (SQLiteDatabaseCorruptException e) {
1692 onCorruption();
1693 throw e;
1694 } finally {
1695 if (statement != null) {
1696 statement.close();
1697 }
1698 unlock();
1699 }
Dan Egnor12311952009-11-23 14:47:45 -08001700 logTimeStat(sql, timeStart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702
1703 @Override
1704 protected void finalize() {
1705 if (isOpen()) {
1706 if (mPrograms.isEmpty()) {
1707 Log.e(TAG, "Leak found", mLeakedException);
1708 } else {
1709 IllegalStateException leakProgram = new IllegalStateException(
1710 "mPrograms size " + mPrograms.size(), mLeakedException);
1711 Log.e(TAG, "Leak found", leakProgram);
1712 }
1713 closeClosable();
1714 onAllReferencesReleased();
1715 }
1716 }
1717
1718 /**
1719 * Private constructor. See {@link #create} and {@link #openDatabase}.
1720 *
1721 * @param path The full path to the database
1722 * @param factory The factory to use when creating cursors, may be NULL.
1723 * @param flags 0 or {@link #NO_LOCALIZED_COLLATORS}. If the database file already
1724 * exists, mFlags will be updated appropriately.
1725 */
1726 private SQLiteDatabase(String path, CursorFactory factory, int flags) {
1727 if (path == null) {
1728 throw new IllegalArgumentException("path should not be null");
1729 }
1730 mFlags = flags;
1731 mPath = path;
Dmitri Plotnikov90142c92009-09-15 10:52:17 -07001732 mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
Dmitri Plotnikov600bdd82009-09-01 12:12:20 -07001733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 mLeakedException = new IllegalStateException(path +
1735 " SQLiteDatabase created and never closed");
1736 mFactory = factory;
1737 dbopen(mPath, mFlags);
Vasu Nori5a03f362009-10-20 15:16:35 -07001738 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1739 mTimeOpened = getTime();
1740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 mPrograms = new WeakHashMap<SQLiteClosable,Object>();
1742 try {
1743 setLocale(Locale.getDefault());
1744 } catch (RuntimeException e) {
1745 Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
1746 dbclose();
Vasu Nori5a03f362009-10-20 15:16:35 -07001747 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1748 mTimeClosed = getTime();
1749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 throw e;
1751 }
1752 }
1753
Vasu Nori5a03f362009-10-20 15:16:35 -07001754 private String getTime() {
1755 return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
1756 }
1757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 /**
1759 * return whether the DB is opened as read only.
1760 * @return true if DB is opened as read only
1761 */
1762 public boolean isReadOnly() {
1763 return (mFlags & OPEN_READ_MASK) == OPEN_READONLY;
1764 }
1765
1766 /**
1767 * @return true if the DB is currently open (has not been closed)
1768 */
1769 public boolean isOpen() {
1770 return mNativeHandle != 0;
1771 }
1772
1773 public boolean needUpgrade(int newVersion) {
1774 return newVersion > getVersion();
1775 }
1776
1777 /**
1778 * Getter for the path to the database file.
1779 *
1780 * @return the path to our database file.
1781 */
1782 public final String getPath() {
1783 return mPath;
1784 }
1785
Vasu Nori5a03f362009-10-20 15:16:35 -07001786
Vasu Nori5a03f362009-10-20 15:16:35 -07001787
Dan Egnor12311952009-11-23 14:47:45 -08001788 /* package */ void logTimeStat(String sql, long beginNanos) {
1789 // Sample fast queries in proportion to the time taken.
1790 // Quantize the % first, so the logged sampling probability
1791 // exactly equals the actual sampling rate for this query.
1792
1793 int samplePercent;
1794 long nanos = Debug.threadCpuTimeNanos() - beginNanos;
1795 if (nanos >= QUERY_LOG_TIME_IN_NANOS) {
1796 samplePercent = 100;
1797 } else {
1798 samplePercent = (int) (100 * nanos / QUERY_LOG_TIME_IN_NANOS) + 1;
Dan Egnor799f7212009-11-24 16:24:44 -08001799 if (mRandom.nextInt(100) >= samplePercent) return;
Dan Egnor12311952009-11-23 14:47:45 -08001800 }
1801
1802 if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
1803
1804 // ActivityThread.currentPackageName() only returns non-null if the
1805 // current thread is an application main thread. This parameter tells
1806 // us whether an event loop is blocked, and if so, which app it is.
1807 //
1808 // Sadly, there's no fast way to determine app name if this is *not* a
1809 // main thread, or when we are invoked via Binder (e.g. ContentProvider).
1810 // Hopefully the full path to the database will be informative enough.
1811
1812 String blockingPackage = ActivityThread.currentPackageName();
1813 if (blockingPackage == null) blockingPackage = "";
1814
1815 int millis = (int) (nanos / 1000000);
1816 EventLog.writeEvent(EVENT_DB_OPERATION, mPath, sql, millis, blockingPackage, samplePercent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 }
1818
1819 /**
1820 * Sets the locale for this database. Does nothing if this database has
1821 * the NO_LOCALIZED_COLLATORS flag set or was opened read only.
1822 * @throws SQLException if the locale could not be set. The most common reason
1823 * for this is that there is no collator available for the locale you requested.
1824 * In this case the database remains unchanged.
1825 */
1826 public void setLocale(Locale locale) {
1827 lock();
1828 try {
1829 native_setLocale(locale.toString(), mFlags);
1830 } finally {
1831 unlock();
1832 }
1833 }
1834
Vasu Norie495d1f2010-01-06 16:34:19 -08001835 /*
1836 * ============================================================================
1837 *
1838 * The following methods deal with compiled-sql cache
1839 * ============================================================================
1840 */
1841 /**
1842 * adds the given sql and its compiled-statement-id-returned-by-sqlite to the
1843 * cache of compiledQueries attached to 'this'.
1844 *
1845 * if there is already a {@link SQLiteCompiledSql} in compiledQueries for the given sql,
1846 * the new {@link SQLiteCompiledSql} object is NOT inserted into the cache (i.e.,the current
1847 * mapping is NOT replaced with the new mapping).
1848 */
1849 /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
1850 if (mMaxSqlCacheSize == 0) {
1851 // for this database, there is no cache of compiled sql.
1852 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1853 Log.v(TAG, "|NOT adding_sql_to_cache|" + getPath() + "|" + sql);
1854 }
1855 return;
1856 }
1857
Vasu Nori994bc222010-01-20 16:36:28 -08001858 /* don't cache PRAGMA sql statements.
1859 * caching them makes sqlite return incorrect results on pragma sql execution!
1860 */
1861 String prefixSql = sql.substring(0, 6);
1862 if (prefixSql.toLowerCase().startsWith("pragma")) {
1863 return;
1864 }
1865
Vasu Norie495d1f2010-01-06 16:34:19 -08001866 SQLiteCompiledSql compiledSql = null;
1867 synchronized(mCompiledQueries) {
1868 // don't insert the new mapping if a mapping already exists
1869 compiledSql = mCompiledQueries.get(sql);
1870 if (compiledSql != null) {
1871 return;
1872 }
1873 // add this <sql, compiledStatement> to the cache
1874 if (mCompiledQueries.size() == mMaxSqlCacheSize) {
1875 /* reached max cachesize. before adding new entry, remove an entry from the
1876 * cache. we don't want to wipe out the entire cache because of this:
1877 * GCing {@link SQLiteCompiledSql} requires call to sqlite3_finalize
1878 * JNI method. If entire cache is wiped out, it could cause a big GC activity
1879 * just because a (rogue) process is using the cache incorrectly.
1880 */
Vasu Norie9d92102010-01-20 15:07:26 -08001881 Log.w(TAG, "Reached MAX size for compiled-sql statement cache for database " +
1882 getPath() + "; i.e., NO space for this sql statement in cache: " +
1883 sql + ". Make sure your sql " +
Vasu Noribee5b9d2010-01-15 10:44:57 -08001884 "statements are using prepared-sql-statement syntax with '?' for " +
Vasu Norie495d1f2010-01-06 16:34:19 -08001885 "bindargs, instead of using actual values");
Vasu Norie9d92102010-01-20 15:07:26 -08001886
1887 /* increment the number of times this warnings has been printed.
1888 * if this warning is printed too many times, clear the whole cache - the app
1889 * is doing something weird or incorrect and printing more warnings will only
1890 * flood the logfile.
1891 */
1892 if (++mCacheFullWarnings > MAX_WARNINGS_ON_CACHESIZE_CONDITION) {
1893 mCacheFullWarnings = 0;
1894 // clear the cache
1895 mCompiledQueries.clear();
Vasu Noriadf1c582010-02-05 15:14:32 -08001896 Log.w(TAG, "Compiled-sql statement cache for database: " +
1897 getPath() + " hit MAX size-limit too many times. " +
1898 "Removing all compiled-sql statements from the cache.");
Vasu Norie9d92102010-01-20 15:07:26 -08001899 } else {
1900 // clear just a single entry from cache
1901 Set<String> keySet = mCompiledQueries.keySet();
1902 for (String s : keySet) {
1903 mCompiledQueries.remove(s);
1904 break;
1905 }
Vasu Norie495d1f2010-01-06 16:34:19 -08001906 }
1907 }
1908 mCompiledQueries.put(sql, compiledStatement);
1909 }
1910 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1911 Log.v(TAG, "|adding_sql_to_cache|" + getPath() + "|" + mCompiledQueries.size() + "|" +
1912 sql);
1913 }
1914 return;
1915 }
1916
1917
1918 private void deallocCachedSqlStatements() {
1919 synchronized (mCompiledQueries) {
1920 for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
1921 compiledSql.releaseSqlStatement();
1922 }
1923 mCompiledQueries.clear();
1924 }
1925 }
1926
1927 /**
1928 * from the compiledQueries cache, returns the compiled-statement-id for the given sql.
1929 * returns null, if not found in the cache.
1930 */
1931 /* package */ SQLiteCompiledSql getCompiledStatementForSql(String sql) {
Vasu Nori994bc222010-01-20 16:36:28 -08001932 // don't look for PRAGMA sql statements in compiled-sql cache
1933 String prefixSql = sql.substring(0, 6);
1934 if (prefixSql.toLowerCase().startsWith("pragma")) {
1935 return null;
1936 }
1937
Vasu Norie495d1f2010-01-06 16:34:19 -08001938 SQLiteCompiledSql compiledStatement = null;
1939 boolean cacheHit;
1940 synchronized(mCompiledQueries) {
1941 if (mMaxSqlCacheSize == 0) {
1942 // for this database, there is no cache of compiled sql.
1943 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1944 Log.v(TAG, "|cache NOT found|" + getPath());
1945 }
1946 return null;
1947 }
1948 cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null;
1949 }
1950 if (cacheHit) {
1951 mNumCacheHits++;
1952 } else {
1953 mNumCacheMisses++;
1954 }
1955
1956 if (SQLiteDebug.DEBUG_SQL_CACHE) {
1957 Log.v(TAG, "|cache_stats|" +
1958 getPath() + "|" + mCompiledQueries.size() +
1959 "|" + mNumCacheHits + "|" + mNumCacheMisses +
1960 "|" + cacheHit + "|" + mTimeOpened + "|" + mTimeClosed + "|" + sql);
1961 }
1962 return compiledStatement;
1963 }
1964
1965 /**
1966 * returns true if the given sql is cached in compiled-sql cache.
1967 * @hide
1968 */
1969 public boolean isInCompiledSqlCache(String sql) {
1970 synchronized(mCompiledQueries) {
1971 return mCompiledQueries.containsKey(sql);
1972 }
1973 }
1974
1975 /**
1976 * purges the given sql from the compiled-sql cache.
1977 * @hide
1978 */
1979 public void purgeFromCompiledSqlCache(String sql) {
1980 synchronized(mCompiledQueries) {
1981 mCompiledQueries.remove(sql);
1982 }
1983 }
1984
1985 /**
1986 * remove everything from the compiled sql cache
1987 * @hide
1988 */
1989 public void resetCompiledSqlCache() {
1990 synchronized(mCompiledQueries) {
1991 mCompiledQueries.clear();
1992 }
1993 }
1994
1995 /**
1996 * return the current maxCacheSqlCacheSize
1997 * @hide
1998 */
1999 public synchronized int getMaxSqlCacheSize() {
2000 return mMaxSqlCacheSize;
2001 }
2002
2003 /**
2004 * set the max size of the compiled sql cache for this database after purging the cache.
2005 * (size of the cache = number of compiled-sql-statements stored in the cache).
2006 *
2007 * max cache size can ONLY be increased from its current size (default = 0).
2008 * if this method is called with smaller size than the current value of mMaxSqlCacheSize,
2009 * then IllegalStateException is thrown
2010 *
2011 * synchronized because we don't want t threads to change cache size at the same time.
2012 * @param cacheSize the size of the cache. can be (0 to MAX_SQL_CACHE_SIZE)
2013 * @throws IllegalStateException if input cacheSize > MAX_SQL_CACHE_SIZE or < 0 or
2014 * < the value set with previous setMaxSqlCacheSize() call.
2015 *
2016 * @hide
2017 */
2018 public synchronized void setMaxSqlCacheSize(int cacheSize) {
2019 if (cacheSize > MAX_SQL_CACHE_SIZE || cacheSize < 0) {
2020 throw new IllegalStateException("expected value between 0 and " + MAX_SQL_CACHE_SIZE);
2021 } else if (cacheSize < mMaxSqlCacheSize) {
2022 throw new IllegalStateException("cannot set cacheSize to a value less than the value " +
2023 "set with previous setMaxSqlCacheSize() call.");
2024 }
2025 mMaxSqlCacheSize = cacheSize;
2026 }
2027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 /**
2029 * Native call to open the database.
2030 *
2031 * @param path The full path to the database
2032 */
2033 private native void dbopen(String path, int flags);
2034
2035 /**
Vasu Nori3ef94e22010-02-05 14:49:04 -08002036 * Native call to setup tracing of all sql statements
2037 *
2038 * @param path the full path to the database
2039 */
2040 private native void enableSqlTracing(String path);
2041
2042 /**
2043 * Native call to setup profiling of all sql statements.
2044 * currently, sqlite's profiling = printing of execution-time
2045 * (wall-clock time) of each of the sql statements, as they
2046 * are executed.
2047 *
2048 * @param path the full path to the database
2049 */
2050 private native void enableSqlProfiling(String path);
2051
2052 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 * Native call to execute a raw SQL statement. {@link #lock} must be held
2054 * when calling this method.
2055 *
2056 * @param sql The raw SQL string
2057 * @throws SQLException
2058 */
2059 /* package */ native void native_execSQL(String sql) throws SQLException;
2060
2061 /**
2062 * Native call to set the locale. {@link #lock} must be held when calling
2063 * this method.
2064 * @throws SQLException
2065 */
2066 /* package */ native void native_setLocale(String loc, int flags);
2067
2068 /**
2069 * Returns the row ID of the last row inserted into the database.
2070 *
2071 * @return the row ID of the last row inserted into the database.
2072 */
2073 /* package */ native long lastInsertRow();
2074
2075 /**
2076 * Returns the number of changes made in the last statement executed.
2077 *
2078 * @return the number of changes made in the last statement executed.
2079 */
2080 /* package */ native int lastChangeCount();
2081}