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