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