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