1 /* 2 * Copyright (C) 2016 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 package androidx.sqlite.db 17 18 import android.annotation.SuppressLint 19 import android.content.ContentValues 20 import android.database.Cursor 21 import android.database.SQLException 22 import android.database.sqlite.SQLiteTransactionListener 23 import android.os.CancellationSignal 24 import android.util.Pair 25 import java.io.Closeable 26 import java.util.Locale 27 28 /** 29 * A database abstraction which removes the framework dependency and allows swapping underlying sql 30 * versions. It mimics the behavior of [android.database.sqlite.SQLiteDatabase] 31 */ 32 public interface SupportSQLiteDatabase : Closeable { 33 /** 34 * Compiles the given SQL statement. 35 * 36 * @param sql The sql query. 37 * @return Compiled statement. 38 */ compileStatementnull39 public fun compileStatement(sql: String): SupportSQLiteStatement 40 41 /** 42 * Begins a transaction in EXCLUSIVE mode. 43 * 44 * Transactions can be nested. When the outer transaction is ended all of the work done in that 45 * transaction and all of the nested transactions will be committed or rolled back. The changes 46 * will be rolled back if any transaction is ended without being marked as clean (by calling 47 * setTransactionSuccessful). Otherwise they will be committed. 48 * 49 * Here is the standard idiom for transactions: 50 * ``` 51 * db.beginTransaction() 52 * try { 53 * ... 54 * db.setTransactionSuccessful() 55 * } finally { 56 * db.endTransaction() 57 * } 58 * ``` 59 */ 60 public fun beginTransaction() 61 62 /** 63 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When the outer 64 * transaction is ended all of the work done in that transaction and all of the nested 65 * transactions will be committed or rolled back. The changes will be rolled back if any 66 * transaction is ended without being marked as clean (by calling setTransactionSuccessful). 67 * Otherwise they will be committed. 68 * 69 * Here is the standard idiom for transactions: 70 * ``` 71 * db.beginTransactionNonExclusive() 72 * try { 73 * ... 74 * db.setTransactionSuccessful() 75 * } finally { 76 * db.endTransaction() 77 * } 78 * ``` 79 */ 80 public fun beginTransactionNonExclusive() 81 82 /** 83 * Begins a transaction in DEFERRED mode, with the android-specific constraint that the 84 * transaction is read-only. The database may not be modified inside a read-only transaction 85 * otherwise a [android.database.sqlite.SQLiteDatabaseLockedException] might be thrown. 86 * 87 * Read-only transactions may run concurrently with other read-only transactions, and if they 88 * database is in WAL mode, they may also run concurrently with IMMEDIATE or EXCLUSIVE 89 * transactions. 90 * 91 * Transactions can be nested. However, the behavior of the transaction is not altered by nested 92 * transactions. A nested transaction may be any of the three transaction types but if the 93 * outermost type is read-only then nested transactions remain read-only, regardless of how they 94 * are started. 95 * 96 * Here is the standard idiom for read-only transactions: 97 * ``` 98 * db.beginTransactionReadOnly(); 99 * try { 100 * ... 101 * } finally { 102 * db.endTransaction(); 103 * } 104 * ``` 105 * 106 * If the implementation does not support read-only transactions then the default implementation 107 * delegates to [beginTransaction]. 108 */ 109 public fun beginTransactionReadOnly() { 110 beginTransaction() 111 } 112 113 /** 114 * Begins a transaction in EXCLUSIVE mode. 115 * 116 * Transactions can be nested. When the outer transaction is ended all of the work done in that 117 * transaction and all of the nested transactions will be committed or rolled back. The changes 118 * will be rolled back if any transaction is ended without being marked as clean (by calling 119 * setTransactionSuccessful). Otherwise they will be committed. 120 * 121 * Here is the standard idiom for transactions: 122 * ``` 123 * db.beginTransactionWithListener(listener) 124 * try { 125 * ... 126 * db.setTransactionSuccessful() 127 * } finally { 128 * db.endTransaction() 129 * } 130 * ``` 131 * 132 * @param transactionListener listener that should be notified when the transaction begins, 133 * commits, or is rolled back, either explicitly or by a call to [yieldIfContendedSafely]. 134 */ beginTransactionWithListenernull135 public fun beginTransactionWithListener(transactionListener: SQLiteTransactionListener) 136 137 /** 138 * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When the outer 139 * transaction is ended all of the work done in that transaction and all of the nested 140 * transactions will be committed or rolled back. The changes will be rolled back if any 141 * transaction is ended without being marked as clean (by calling setTransactionSuccessful). 142 * Otherwise they will be committed. 143 * 144 * Here is the standard idiom for transactions: 145 * ``` 146 * db.beginTransactionWithListenerNonExclusive(listener) 147 * try { 148 * ... 149 * db.setTransactionSuccessful() 150 * } finally { 151 * db.endTransaction() 152 * } 153 * ``` 154 * 155 * @param transactionListener listener that should be notified when the transaction begins, 156 * commits, or is rolled back, either explicitly or by a call to [yieldIfContendedSafely]. 157 */ 158 public fun beginTransactionWithListenerNonExclusive( 159 transactionListener: SQLiteTransactionListener 160 ) 161 162 /** 163 * Begins a transaction in read-only mode with a {@link SQLiteTransactionListener} listener. The 164 * database may not be modified inside a read-only transaction otherwise a 165 * [android.database.sqlite.SQLiteDatabaseLockedException] might be thrown. 166 * 167 * Transactions can be nested. However, the behavior of the transaction is not altered by nested 168 * transactions. A nested transaction may be any of the three transaction types but if the 169 * outermost type is read-only then nested transactions remain read-only, regardless of how they 170 * are started. 171 * 172 * Here is the standard idiom for read-only transactions: 173 * ``` 174 * db.beginTransactionWightListenerReadOnly(listener); 175 * try { 176 * ... 177 * } finally { 178 * db.endTransaction(); 179 * } 180 * ``` 181 * 182 * If the implementation does not support read-only transactions then the default implementation 183 * delegates to [beginTransactionWithListener]. 184 */ 185 @Suppress("ExecutorRegistration") 186 public fun beginTransactionWithListenerReadOnly( 187 transactionListener: SQLiteTransactionListener 188 ) { 189 beginTransactionWithListener(transactionListener) 190 } 191 192 /** 193 * End a transaction. See beginTransaction for notes about how to use this and when transactions 194 * are committed and rolled back. 195 */ endTransactionnull196 public fun endTransaction() 197 198 /** 199 * Marks the current transaction as successful. Do not do any more database work between calling 200 * this and calling endTransaction. Do as little non-database work as possible in that situation 201 * too. If any errors are encountered between this and endTransaction the transaction will still 202 * be committed. 203 * 204 * @throws IllegalStateException if the current thread is not in a transaction or the 205 * transaction is already marked as successful. 206 */ 207 public fun setTransactionSuccessful() 208 209 /** 210 * Returns true if the current thread has a transaction pending. 211 * 212 * @return True if the current thread is in a transaction. 213 */ 214 public fun inTransaction(): Boolean 215 216 /** 217 * True if the current thread is holding an active connection to the database. 218 * 219 * The name of this method comes from a time when having an active connection to the database 220 * meant that the thread was holding an actual lock on the database. Nowadays, there is no 221 * longer a true "database lock" although threads may block if they cannot acquire a database 222 * connection to perform a particular operation. 223 */ 224 public val isDbLockedByCurrentThread: Boolean 225 226 /** 227 * Temporarily end the transaction to let other threads run. The transaction is assumed to be 228 * successful so far. Do not call setTransactionSuccessful before calling this. When this 229 * returns a new transaction will have been created but not marked as successful. This assumes 230 * that there are no nested transactions (beginTransaction has only been called once) and will 231 * throw an exception if that is not the case. 232 * 233 * @return true if the transaction was yielded 234 */ 235 public fun yieldIfContendedSafely(): Boolean 236 237 /** 238 * Temporarily end the transaction to let other threads run. The transaction is assumed to be 239 * successful so far. Do not call setTransactionSuccessful before calling this. When this 240 * returns a new transaction will have been created but not marked as successful. This assumes 241 * that there are no nested transactions (beginTransaction has only been called once) and will 242 * throw an exception if that is not the case. 243 * 244 * @param sleepAfterYieldDelayMillis if > 0, sleep this long before starting a new transaction 245 * if the lock was actually yielded. This will allow other background threads to make some 246 * more progress than they would if we started the transaction immediately. 247 * @return true if the transaction was yielded 248 */ 249 public fun yieldIfContendedSafely(sleepAfterYieldDelayMillis: Long): Boolean 250 251 /** Is true if [execPerConnectionSQL] is supported by the implementation. */ 252 public val isExecPerConnectionSQLSupported: Boolean 253 get() = false 254 255 /** 256 * Execute the given SQL statement on all connections to this database. 257 * 258 * This statement will be immediately executed on all existing connections, and will be 259 * automatically executed on all future connections. 260 * 261 * Some example usages are changes like `PRAGMA trusted_schema=OFF` or functions like `SELECT 262 * icu_load_collation()`. If you execute these statements using [execSQL] then they will only 263 * apply to a single database connection; using this method will ensure that they are uniformly 264 * applied to all current and future connections. 265 * 266 * An implementation of [SupportSQLiteDatabase] might not support this operation. Use 267 * [isExecPerConnectionSQLSupported] to check if this operation is supported before calling this 268 * method. 269 * 270 * @param sql The SQL statement to be executed. Multiple statements separated by semicolons are 271 * not supported. 272 * @param bindArgs The arguments that should be bound to the SQL statement. 273 * @throws UnsupportedOperationException if this operation is not supported. To check if it 274 * supported use [isExecPerConnectionSQLSupported] 275 */ 276 public fun execPerConnectionSQL( 277 sql: String, 278 @SuppressLint("ArrayReturn") bindArgs: Array<out Any?>? 279 ) { 280 throw UnsupportedOperationException() 281 } 282 283 /** The database version. */ 284 public var version: Int 285 286 /** The maximum size the database may grow to. */ 287 public val maximumSize: Long 288 289 /** 290 * Sets the maximum size the database will grow to. The maximum size cannot be set below the 291 * current size. 292 * 293 * @param numBytes the maximum database size, in bytes 294 * @return the new maximum database size 295 */ setMaximumSizenull296 public fun setMaximumSize(numBytes: Long): Long 297 298 /** 299 * The current database page size, in bytes. 300 * 301 * The page size must be a power of two. This method does not work if any data has been written 302 * to the database file, and must be called right after the database has been created. 303 */ 304 public var pageSize: Long 305 306 /** 307 * Runs the given query on the database. If you would like to have typed bind arguments, use 308 * [query]. 309 * 310 * @param query The SQL query that includes the query and can bind into a given compiled 311 * program. 312 * @return A [Cursor] object, which is positioned before the first entry. Note that [Cursor]s 313 * are not synchronized, see the documentation for more details. 314 */ 315 public fun query(query: String): Cursor 316 317 /** 318 * Runs the given query on the database. If you would like to have bind arguments, use [query]. 319 * 320 * @param query The SQL query that includes the query and can bind into a given compiled 321 * program. 322 * @param bindArgs The query arguments to bind. 323 * @return A [Cursor] object, which is positioned before the first entry. Note that [Cursor]s 324 * are not synchronized, see the documentation for more details. 325 */ 326 public fun query(query: String, bindArgs: Array<out Any?>): Cursor 327 328 /** 329 * Runs the given query on the database. 330 * 331 * This class allows using type safe sql program bindings while running queries. 332 * 333 * @param query The [SimpleSQLiteQuery] query that includes the query and can bind into a given 334 * compiled program. 335 * @return A [Cursor] object, which is positioned before the first entry. Note that [Cursor]s 336 * are not synchronized, see the documentation for more details. 337 */ 338 public fun query(query: SupportSQLiteQuery): Cursor 339 340 /** 341 * Runs the given query on the database. 342 * 343 * This class allows using type safe sql program bindings while running queries. 344 * 345 * @param query The SQL query that includes the query and can bind into a given compiled 346 * program. 347 * @param cancellationSignal A signal to cancel the operation in progress, or null if none. If 348 * the operation is canceled, then [androidx.core.os.OperationCanceledException] will be 349 * thrown when the query is executed. 350 * @return A [Cursor] object, which is positioned before the first entry. Note that [Cursor]s 351 * are not synchronized, see the documentation for more details. 352 */ 353 public fun query(query: SupportSQLiteQuery, cancellationSignal: CancellationSignal?): Cursor 354 355 /** 356 * Convenience method for inserting a row into the database. 357 * 358 * @param table the table to insert the row into 359 * @param values this map contains the initial column values for the row. The keys should be the 360 * column names and the values the column values 361 * @param conflictAlgorithm for insert conflict resolver. One of 362 * [android.database.sqlite.SQLiteDatabase.CONFLICT_NONE], 363 * [android.database.sqlite.SQLiteDatabase.CONFLICT_ROLLBACK], 364 * [android.database.sqlite.SQLiteDatabase.CONFLICT_ABORT], 365 * [android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL], 366 * [android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE], 367 * [android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE]. 368 * @return the row ID of the newly inserted row, or -1 if an error occurred 369 * @throws SQLException If the insert fails 370 */ 371 @Throws(SQLException::class) 372 public fun insert(table: String, conflictAlgorithm: Int, values: ContentValues): Long 373 374 /** 375 * Convenience method for deleting rows in the database. 376 * 377 * @param table the table to delete from 378 * @param whereClause the optional WHERE clause to apply when deleting. Passing null will delete 379 * all rows. 380 * @param whereArgs You may include ?s in the where clause, which will be replaced by the values 381 * from whereArgs. The values will be bound as Strings. 382 * @return the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all 383 * rows and get a count pass "1" as the whereClause. 384 */ 385 public fun delete(table: String, whereClause: String?, whereArgs: Array<out Any?>?): Int 386 387 /** 388 * Convenience method for updating rows in the database. 389 * 390 * @param table the table to update in 391 * @param conflictAlgorithm for update conflict resolver. One of 392 * [android.database.sqlite.SQLiteDatabase.CONFLICT_NONE], 393 * [android.database.sqlite.SQLiteDatabase.CONFLICT_ROLLBACK], 394 * [android.database.sqlite.SQLiteDatabase.CONFLICT_ABORT], 395 * [android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL], 396 * [android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE], 397 * [android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE]. 398 * @param values a map from column names to new column values. null is a valid value that will 399 * be translated to NULL. 400 * @param whereClause the optional WHERE clause to apply when updating. Passing null will update 401 * all rows. 402 * @param whereArgs You may include ?s in the where clause, which will be replaced by the values 403 * from whereArgs. The values will be bound as Strings. 404 * @return the number of rows affected 405 */ 406 public fun update( 407 table: String, 408 conflictAlgorithm: Int, 409 values: ContentValues, 410 whereClause: String?, 411 whereArgs: Array<out Any?>? 412 ): Int 413 414 /** 415 * Execute a single SQL statement that does not return any data. 416 * 417 * When using [enableWriteAheadLogging], journal_mode is automatically managed by this class. 418 * So, do not set journal_mode using "PRAGMA journal_mode" statement if your app is using 419 * [enableWriteAheadLogging] 420 * 421 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 422 * not supported. 423 * @throws SQLException if the SQL string is invalid 424 */ 425 @Throws(SQLException::class) public fun execSQL(sql: String) 426 427 /** 428 * Execute a single SQL statement that does not return any data. 429 * 430 * When using [enableWriteAheadLogging], journal_mode is automatically managed by this class. 431 * So, do not set journal_mode using "PRAGMA journal_mode" statement if your app is using 432 * [enableWriteAheadLogging] 433 * 434 * @param sql the SQL statement to be executed. Multiple statements separated by semicolons are 435 * not supported. 436 * @param bindArgs only byte[], String, Long and Double are supported in selectionArgs. 437 * @throws SQLException if the SQL string is invalid 438 */ 439 @Throws(SQLException::class) public fun execSQL(sql: String, bindArgs: Array<out Any?>) 440 441 /** Is true if the database is opened as read only. */ 442 public val isReadOnly: Boolean 443 444 /** Is true if the database is currently open. */ 445 public val isOpen: Boolean 446 447 /** 448 * Returns true if the new version code is greater than the current database version. 449 * 450 * @param newVersion The new version code. 451 * @return True if the new version code is greater than the current database version. 452 */ 453 public fun needUpgrade(newVersion: Int): Boolean 454 455 /** The path to the database file. */ 456 public val path: String? 457 458 /** 459 * Sets the locale for this database. Does nothing if this database has the 460 * [android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS] flag set or was opened read 461 * only. 462 * 463 * @param locale The new locale. 464 * @throws SQLException if the locale could not be set. The most common reason for this is that 465 * there is no collator available for the locale you requested. In this case the database 466 * remains unchanged. 467 */ 468 public fun setLocale(locale: Locale) 469 470 /** 471 * Sets the maximum size of the prepared-statement cache for this database. (size of the cache = 472 * number of compiled-sql-statements stored in the cache). 473 * 474 * Maximum cache size can ONLY be increased from its current size (default = 10). If this method 475 * is called with smaller size than the current maximum value, then IllegalStateException is 476 * thrown. 477 * 478 * This method is thread-safe. 479 * 480 * @param cacheSize the size of the cache. can be (0 to 481 * [android.database.sqlite.SQLiteDatabase.MAX_SQL_CACHE_SIZE]) 482 * @throws IllegalStateException if input cacheSize is over the max. 483 * [android.database.sqlite.SQLiteDatabase.MAX_SQL_CACHE_SIZE]. 484 */ 485 public fun setMaxSqlCacheSize(cacheSize: Int) 486 487 /** 488 * Sets whether foreign key constraints are enabled for the database. 489 * 490 * By default, foreign key constraints are not enforced by the database. This method allows an 491 * application to enable foreign key constraints. It must be called each time the database is 492 * opened to ensure that foreign key constraints are enabled for the session. 493 * 494 * A good time to call this method is right after calling `#openOrCreateDatabase` or in the 495 * [SupportSQLiteOpenHelper.Callback.onConfigure] callback. 496 * 497 * When foreign key constraints are disabled, the database does not check whether changes to the 498 * database will violate foreign key constraints. Likewise, when foreign key constraints are 499 * disabled, the database will not execute cascade delete or update triggers. As a result, it is 500 * possible for the database state to become inconsistent. To perform a database integrity 501 * check, call [isDatabaseIntegrityOk]. 502 * 503 * This method must not be called while a transaction is in progress. 504 * 505 * See also [SQLite Foreign Key Constraints](http://sqlite.org/foreignkeys.html) for more 506 * details about foreign key constraint support. 507 * 508 * @param enabled True to enable foreign key constraints, false to disable them. 509 * @throws IllegalStateException if the are transactions is in progress when this method is 510 * called. 511 */ 512 public fun setForeignKeyConstraintsEnabled(enabled: Boolean) 513 514 /** 515 * This method enables parallel execution of queries from multiple threads on the same database. 516 * It does this by opening multiple connections to the database and using a different database 517 * connection for each query. The database journal mode is also changed to enable writes to 518 * proceed concurrently with reads. 519 * 520 * When write-ahead logging is not enabled (the default), it is not possible for reads and 521 * writes to occur on the database at the same time. Before modifying the database, the writer 522 * implicitly acquires an exclusive lock on the database which prevents readers from accessing 523 * the database until the write is completed. 524 * 525 * In contrast, when write-ahead logging is enabled (by calling this method), write operations 526 * occur in a separate log file which allows reads to proceed concurrently. While a write is in 527 * progress, readers on other threads will perceive the state of the database as it was before 528 * the write began. When the write completes, readers on other threads will then perceive the 529 * new state of the database. 530 * 531 * It is a good idea to enable write-ahead logging whenever a database will be concurrently 532 * accessed and modified by multiple threads at the same time. However, write-ahead logging uses 533 * significantly more memory than ordinary journaling because there are multiple connections to 534 * the same database. So if a database will only be used by a single thread, or if optimizing 535 * concurrency is not very important, then write-ahead logging should be disabled. 536 * 537 * After calling this method, execution of queries in parallel is enabled as long as the 538 * database remains open. To disable execution of queries in parallel, either call 539 * [disableWriteAheadLogging] or close the database and reopen it. 540 * 541 * The maximum number of connections used to execute queries in parallel is dependent upon the 542 * device memory and possibly other properties. 543 * 544 * If a query is part of a transaction, then it is executed on the same database handle the 545 * transaction was begun. 546 * 547 * Writers should use [beginTransactionNonExclusive] or 548 * [beginTransactionWithListenerNonExclusive] to start a transaction. Non-exclusive mode allows 549 * database file to be in readable by other threads executing queries. 550 * 551 * If the database has any attached databases, then execution of queries in parallel is NOT 552 * possible. Likewise, write-ahead logging is not supported for read-only databases or memory 553 * databases. In such cases, `enableWriteAheadLogging` returns false. 554 * 555 * The best way to enable write-ahead logging is to pass the 556 * [android.database.sqlite.SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING] flag to 557 * [android.database.sqlite.SQLiteDatabase.openDatabase]. This is more efficient than calling 558 * 559 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, 560 * SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING, 561 * myDatabaseErrorHandler) db.enableWriteAheadLogging() 562 * 563 * Another way to enable write-ahead logging is to call `enableWriteAheadLogging` after opening 564 * the database. 565 * 566 * SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory, 567 * SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler) db.enableWriteAheadLogging() 568 * 569 * See also [SQLite Write-Ahead Logging](http://sqlite.org/wal.html) for more details about how 570 * write-ahead logging works. 571 * 572 * @return True if write-ahead logging is enabled. 573 * @throws IllegalStateException if there are transactions in progress at the time this method 574 * is called. WAL mode can only be changed when there are no transactions in progress. 575 */ 576 public fun enableWriteAheadLogging(): Boolean 577 578 /** 579 * This method disables the features enabled by [enableWriteAheadLogging]. 580 * 581 * @throws IllegalStateException if there are transactions in progress at the time this method 582 * is called. WAL mode can only be changed when there are no transactions in progress. 583 */ 584 public fun disableWriteAheadLogging() 585 586 /** Is true if write-ahead logging has been enabled for this database. */ 587 public val isWriteAheadLoggingEnabled: Boolean 588 589 /** 590 * The list of full path names of all attached databases including the main database by 591 * executing 'pragma database_list' on the database. 592 */ 593 @get:Suppress("NullableCollection") public val attachedDbs: List<Pair<String, String>>? 594 595 /** 596 * Is true if the given database (and all its attached databases) pass integrity_check, false 597 * otherwise. 598 */ 599 public val isDatabaseIntegrityOk: Boolean 600 } 601