Android - What value is returned by the insert convenience method for a WITHOUT ROWID table?

MikeT :

Note This Question is intended to be a share your knowledge, Q&A-style.

SQLite by default creates a hidden column namely rowid which will be assigned a unique 64 bit signed integer value.

However, since SQLite version 3.8.2, SQLite has supported the WITHOUT ROWID clause, which results in the rowid being omitted.

What would the result be, assuming a successful insert?

i.e. the long returned from the SQLiteDatabase insert family (insert, insertOrThrow and insertWithOnConflict) as per :-

the row ID of the newly inserted row, or -1 if an error occurred

SQLiteDatabase - insert

MikeT :

As SQLite version 3.8.2 or greater is only available since API 21 Lollilop, then WITHOUT ROWID can only be used from API 21 on.

Prior to API 21 coding WITHOUT ROWID would result in a syntax error, so a result would not be possible as such a table cannot exist.

Since API 21 then the result is that 0 is returned, if the insert worked else -1.

However, that is just assuming a simple case of a single table or multiple WITHOUT ROWID tables (i.e. no ROWID tables).

Adding ROWID tables into the mix, which would be the more likely scenario, then the result is as per the previous time, since the database was opened, that a result was set (as per SQLite rather than the Android SDK) or -1.

In short, the value if not -1, indicates that a row was inserted (very likely), -1 would typically indicate that the row was not inserted.

  • caveat if you force a rowid to be -1 (supply -1 for the rowid column directly or via an alias) then a result of -1 could be returned, even though the row was inserted.

Example

The following demonstrates the creation of a database with a single WITHOUT ROWID table, in which two rows are inserted and the result is output to the log. A subclass of SQLiteOpenHelper is used as this appears to be the more common means of accessing SQLite Database.

DBHelperNoRowid.java (Database Helper)

public class DBHelperNoRowid extends SQLiteOpenHelper {

    public final static String DB = "test_norowid";
    public static final int VERSION = 1;
    public static final String TBL_NOROWID = "norowid";
    public static final String COL_ID = BaseColumns._ID;
    public static final String COL_MYDATA = "mydata";

    SQLiteDatabase mDB;

    public DBHelperNoRowid(Context context) {
        super(context, DB, null, VERSION);
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String crt_norowid_table = "CREATE TABLE IF NOT EXISTS " + TBL_NOROWID + "(" +
                COL_ID + " INTEGER PRIMARY KEY, " +
                COL_MYDATA + " TEXT" +
                ") WITHOUT ROWID"; //<<<<<<<<<<
        db.execSQL(crt_norowid_table);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public long insertUsingConvenienceInsert(long not_an_id, String text) {
        ContentValues cv = new ContentValues();
        cv.put(COL_ID,not_an_id);
        cv.put(COL_MYDATA,text);
        return mDB.insert(TBL_NOROWID,null,cv);
    }
}

MainActivty.java

public class MainActivity extends AppCompatActivity {

    DBHelperNoRowid mDBhlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDBhlpr = new DBHelperNoRowid(this);
        logInsertResult(2100L,"row 1");
        logInsertResult(-898765432,"row 2");
    }

    private void logInsertResult(long not_an_id, String text) {

        Log.d("INSERTRESULT","Insertion of a row returned " + String.valueOf(
                mDBhlpr.insertUsingConvenienceInsert(not_an_id,text)
        ));
    }
}

Result

2019-01-23 17:36:04.029 24175-24175/so.uru D/INSERTRESULT: Insertion of a row returned 0
2019-01-23 17:36:04.029 24175-24175/so.uru D/INSERTRESULT: Insertion of a row returned 0

Second run

Running the above will result in the UNIQUE constraint conflict, which will be trapped by the insert method, and then -1 will be returned e.g. :-

2019-01-23 19:49:51.915 24876-24876/so.uru E/SQLiteDatabase: Error inserting _id=2100 mydata=row 1
    android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: norowid._id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1564)
        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
        at so.uru.DBHelperNoRowid.insertUsingConvenienceInsert(DBHelperNoRowid.java:42)
        at so.uru.MainActivity.logInsertResult(MainActivity.java:23)
        at so.uru.MainActivity.onCreate(MainActivity.java:16)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-01-23 19:49:51.916 24876-24876/so.uru D/INSERTRESULT: Insertion of a row returned -1
2019-01-23 19:49:51.918 24876-24876/so.uru E/SQLiteDatabase: Error inserting _id=-898765432 mydata=row 2
    android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: norowid._id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)
        at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
        at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
        at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1564)
        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
        at so.uru.DBHelperNoRowid.insertUsingConvenienceInsert(DBHelperNoRowid.java:42)
        at so.uru.MainActivity.logInsertResult(MainActivity.java:23)
        at so.uru.MainActivity.onCreate(MainActivity.java:17)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-01-23 19:49:51.918 24876-24876/so.uru D/INSERTRESULT: Insertion of a row returned -1

Code used for testing a mix of rowid and without tables

  • Note the following is just one of the multiple permutations used for testing:-

DBHelperBoRowid.java

public class DBHelperNoRowid extends SQLiteOpenHelper {

    public final static String DB = "test_norowid";
    public static final int VERSION = 1;
    public static final String TBL_NOROWID = "norowid";
    public static final String COL_ID = BaseColumns._ID;
    public static final String COL_MYDATA = "mydata";
    public static final String TBL_WITHROWID = "withrowid";

    SQLiteDatabase mDB;

    public DBHelperNoRowid(Context context) {
        super(context, DB, null, VERSION);
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String crt_norowid_table = "CREATE TABLE IF NOT EXISTS " + TBL_NOROWID + "(" +
                COL_ID + " INTEGER PRIMARY KEY, " +
                COL_MYDATA + " TEXT" +
                ") WITHOUT ROWID";
        db.execSQL(crt_norowid_table);
        String crt_withrowid_table = "CREATE TABLE IF NOT EXISTS " + TBL_WITHROWID + "(" +
                COL_ID + " INTEGER PRIMARY KEY, " +
                COL_MYDATA + " TEXT" +
                ")";
        db.execSQL(crt_withrowid_table);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public long insertUsingConvenienceInsert(long not_an_id, String text, boolean without_rowid, boolean generate_rowid) {
        ContentValues cv = new ContentValues();
        String table = TBL_WITHROWID;
        if (without_rowid) {
            table = TBL_NOROWID;
            cv.put(COL_ID,not_an_id);
        } else {
            if (generate_rowid) {
                cv.put(COL_ID,not_an_id);
            }
        }
        cv.put(COL_MYDATA,text);
        return mDB.insert(table,null,cv);
    }

    public void logLastInsertId() {
        Cursor csr = mDB.rawQuery("SELECT last_insert_rowid()",null);
        if (csr.moveToFirst()) {
            Log.d("LASTINSERTEDROWID","The Last RowID inserted was " + String.valueOf(csr.getLong(0)));
        } else {
            Log.d("LASTINSERTEDROWID","Ooops there does not appear to have been a row inserted");
        }
    }
}

MainActivity.java (as per the last permutation used)

public class MainActivity extends AppCompatActivity {

    DBHelperNoRowid mDBhlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDBhlpr = new DBHelperNoRowid(this);
        // Insert some rows into the table that is a rowid table
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(-1,"row 1",false,true);

        logInsertResult(2100L,"row 1",true,true); //<<<<<<<<<< WITHOUT

        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);

        logInsertResult(-898765432,"row 2",true,true); //<<<<<<<<<< WITHOUT

        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);
        logInsertResult(1,"row 1",false,false);

        logInsertResult(-1L,"3rd row",true,true); //<<<<<<<<<< WITHOUT
    }

    private void logInsertResult(long no_an_id, String text, boolean without_rowid, boolean generate_rowid) {

        if (without_rowid) {
            Log.d("INSERTRESULT",">>>>>>>>>> WITHOUT ROWID ATTEMPT");
        }

        Log.d("INSERTRESULT","Insertion of a row returned " + String.valueOf(
                mDBhlpr.insertUsingConvenienceInsert(no_an_id,text,without_rowid,generate_rowid)
        ));
        mDBhlpr.logLastInsertId(); //
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=101808&siteId=1