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