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