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