Search code examples
javaandroidsambasqliteopenhelper

SqLiteDatabase writable Vs. ReadOnly


I don't get any sense why they are writing two opposite variables in Logical OR. True || False = True, or False || True = True. Why this check is necessary?

if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!writable || !mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }

Note: The same logic is applied in Samba file share also. There is a Samba explanation http://www.linuxtopia.org/online_books/network_administration_guides/using_samba_book/ch04_05_06.html

Can anyone clarify me here?

The code stub I presented above is in SQLiteOpenHelper class from line 222 to 231

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteOpenHelper.java


Solution

  • Writable is defined by:

    1. If the disk is R-W
    2. If the process that writes to database has write permission.

    Note: Writable has nothing to do with your understanding here.

    For the ReadOnly, there is a logic because ReadOnly is not opposite of Writable. This is where you are confused.

    There are three things in ReadOnly: OPEN_READONLY, OPEN_READ_MASK, and OpenFlags.

    Note: OPEN_READONLY is exactly opposite of Writable. This is where you were unclear.

    Explanation OPEN_READ_MASK -- We set it to 1 (i.e. 0X00000001 in Hex) OPEN_READONLY -- We set it to 1 (i.e. 0X00000001 in Hex)

    OpenFlags - Sometimes it is 1, sometimes it is 0. It is 1 if the disk not not full. It is 0 if the disk is full.

    And, we calculate ReadOnly = (OpenFlags & OPEN_READ_MASK == OPEN_READONLY). Now, from this & operation, the ReadOnly always ensures even though the database is OPEN_READONLY, still it needs to satisfy it is not full. If it is full then ReadOnly becomes false.

    That's why for every file and database, the above implemented & operation is reliable.

    Proof:

    If you ctrl+Alt click the method of isReadOnly(), you will see below lines of code.

    public boolean isReadOnly() {
            synchronized (mLock) {
                return isReadOnlyLocked();
            }
        }
    

    You further Ctrl+Alt+click on method isReadOnlyLocked(), you will see below lines of code.

    private boolean isReadOnlyLocked() {
            return (mConfigurationLocked.openFlags & OPEN_READ_MASK) == OPEN_READONLY;
        }
    

    You can see how OPEN_READ_MASK and OPEN_READONLY defined by further Ctrl+Alt+click, you see below lines of code.

    /**
         * Open flag: Flag for {@link #openDatabase} to open the database for reading only.
         * This is the only reliable way to open a database if the disk may be full.
         */
        public static final int OPEN_READONLY = 0x00000001;           // update native code if changing
    
        private static final int OPEN_READ_MASK = 0x00000001;         // update native code if changing
    

    If the disk is full, they system changes openFlags to 0 to ensure even though the disk is Openly readOnly still because of there is no disk space, you can't write. Now, I believe, you are clear.