Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Column xxxx is not unique. #232

Closed
Moussawi7 opened this issue Apr 6, 2015 · 8 comments
Closed

Android: Column xxxx is not unique. #232

Moussawi7 opened this issue Apr 6, 2015 · 8 comments

Comments

@Moussawi7
Copy link

when I try to insert a row having an index already exists in the table where this index is unique, an exception occurred which prevent me to continue using the plugin.
_Note:_ I was using an old version of this plugin and this issue never happened
Thank you.
sample code:

create table users(
id integer PRIMARY KEY AUTOINCREMENT,
user_id integer
);
CREATE UNIQUE INDEX users_index on users (user_id);

and this is the error log:

04-06 06:28:06.014: D/dalvikvm(15344): GC_FOR_ALLOC freed 678K, 18% free 3301K/4012K, paused 0ms, total 0ms
04-06 06:28:06.064: W/PluginManager(15344): THREAD WARNING: exec() call to SQLitePlugin.backgroundExecuteSqlBatch blocked the main thread for 50ms. Plugin should use CordovaInterface.getThreadPool().
04-06 06:28:06.174: D/dalvikvm(15344): GC_FOR_ALLOC freed 914K, 23% free 3325K/4272K, paused 0ms, total 0ms
04-06 06:28:06.334: D/CordovaLog(15344): file:///android_asset/www/plugins/com.brodysoft.sqlitePlugin/www/SQLitePlugin.js: Line 164 : database already open: DB-v2
04-06 06:28:06.334: I/chromium(15344): [INFO:CONSOLE(164)] "database already open: DB-v2", source: file:///android_asset/www/plugins/com.brodysoft.sqlitePlugin/www/SQLitePlugin.js (164)
04-06 06:28:06.344: D/CordovaLog(15344): file:///android_asset/www/plugins/com.brodysoft.sqlitePlugin/www/SQLitePlugin.js: Line 76 : DB opened: DB-v2
04-06 06:28:06.344: I/chromium(15344): [INFO:CONSOLE(76)] "DB opened: DB-v2", source: file:///android_asset/www/plugins/com.brodysoft.sqlitePlugin/www/SQLitePlugin.js (76)
04-06 06:28:08.154: V/GCMRegistrar(15344): Saving regId on app version 1
04-06 06:28:08.154: V/GCMIntentService(15344): onRegistered: APA91bEFc2bCbBBfirmqLSz5w_NYFMrt-MwOZHTW9SvA3T7aGGaLrn6Tr2V1CD74sDNRb6TYAlFKtP_xlsmzZ-YfgEiWV-jwqSVFVINxa5AUBf7C6UU_RgYivVUTMXd5oQhkJLSbrk5h-qyIQ74wwBOZEuoDAS9coA
04-06 06:28:08.154: V/GCMIntentService(15344): onRegistered: {"regid":"APA91bEFc2bCbBBfirmqLSz5w_NYFMrt-MwOZHTW9SvA3T7aGGaLrn6Tr2V1CD74sDNRb6TYAlFKtP_xlsmzZ-YfgEiWV-jwqSVFVINxa5AUBf7C6UU_RgYivVUTMXd5oQhkJLSbrk5h-qyIQ74wwBOZEuoDAS9coA","event":"registered"}
04-06 06:28:08.154: V/PushPlugin(15344): sendJavascript: javascript:plugin_remote_notification.receive_notification_gcm({"regid":"APA91bEFc2bCbBBfirmqLSz5w_NYFMrt-MwOZHTW9SvA3T7aGGaLrn6Tr2V1CD74sDNRb6TYAlFKtP_xlsmzZ-YfgEiWV-jwqSVFVINxa5AUBf7C6UU_RgYivVUTMXd5oQhkJLSbrk5h-qyIQ74wwBOZEuoDAS9coA","event":"registered"})
04-06 06:28:08.154: V/GCMBaseIntentService(15344): Releasing wakelock
04-06 06:28:15.584: W/PluginManager(15344): THREAD WARNING: exec() call to SQLitePlugin.backgroundExecuteSqlBatch blocked the main thread for 20ms. Plugin should use CordovaInterface.getThreadPool().
04-06 06:28:15.604: D/FileTransfer(15344): download http://et3-uploads
04-06 06:28:17.464: W/System.err(15344): android.database.sqlite.SQLiteConstraintException: column user_id is not unique (code 19)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin.executeSqlBatch(SQLitePlugin.java:491)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin.access$1(SQLitePlugin.java:412)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin$DBRunner.run(SQLitePlugin.java:856)
04-06 06:28:17.464: W/System.err(15344):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
04-06 06:28:17.464: W/System.err(15344):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
04-06 06:28:17.464: W/System.err(15344):    at java.lang.Thread.run(Thread.java:841)
04-06 06:28:17.464: V/executeSqlBatch(15344): SQLiteDatabase.executeInsert(): Error=column user_id is not unique (code 19)
04-06 06:28:17.464: W/System.err(15344): android.database.sqlite.SQLiteConstraintException: column user_id is not unique (code 19)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
04-06 06:28:17.464: W/System.err(15344):    at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin.executeSqlBatch(SQLitePlugin.java:491)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin.access$1(SQLitePlugin.java:412)
04-06 06:28:17.464: W/System.err(15344):    at org.pgsqlite.SQLitePlugin$DBRunner.run(SQLitePlugin.java:856)
04-06 06:28:17.464: W/System.err(15344):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
04-06 06:28:17.464: W/System.err(15344):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
04-06 06:28:17.464: W/System.err(15344):    at java.lang.Thread.run(Thread.java:841)
04-06 06:28:17.464: V/executeSqlBatch(15344): SQLiteDatabase.executeInsert(): Error=column user_id is not unique (code 19)
04-06 06:28:17.484: D/dalvikvm(15344): GC_FOR_ALLOC freed 510K, 20% free 3604K/4452K, paused 10ms, total 10ms
@brodycj
Copy link

brodycj commented Apr 6, 2015

This is the correct behavior. In case of any doubt you can try the same thing on a Web SQL database opened with windows.openDatabase().

@Moussawi7
Copy link
Author

Hi @brodybits ,
Yeah, you are right, sure the row should not be inserted since the key is unique.
but the problem here that the row is not inserted(true) but the transaction throw an error which interrupt the execution.

this.instance = window.sqlitePlugin.openDatabase({name: "DB-v2"});
   insert_user_bulk= function (context, data, callback) {
        var counter = 0;
        this.instance.transaction(function (tx) {
            for (var i = 0; i < data.length; i++) {
                var sql = "insert into users(user_id) values (?)";
                tx.executeSql(sql,[data[i]], function () {
                    counter++;
                    if (counter === data.length) {
                        callback.call(context);
                    }
                }, function () {
//Here should be fired if row could not be inserted
                    counter++;
                    if (counter === data.length) {
                        callback.call(context);
                    }
                });
            }
        }, function(){
            console.log("transaction error");// this is fired when i try to insert a row with existing user_id.
        });
    };

@brodycj
Copy link

brodycj commented Apr 8, 2015

This issue is due to a misunderstanding of the W3 database (draft) specification in PR #170. Will be fixed later this week. (I do see the executeSql error callback get fired.) As a workaround: in the executeSql error callback, if you return false the transaction error callback will not be fired.

@aarononeal
Copy link
Contributor

The spec says:

In case of error, run the following substeps:

  1. If the statement had an associated error callback that is not null, then queue a task to invoke that error callback ...
  2. If the error callback returns false, then move on to the next statement, if any, or onto the next overall step otherwise. [continue execution]
  3. Otherwise, the error callback did not return false, or there was no error callback. Jump to the last step in the overall steps. [rollback and fail]

The last step in the overall steps is:

Queue a task to invoke the transaction's error callback, if it is not null, with a newly constructed SQLError object that represents the last error to have occurred in this transaction. Rollback the transaction. Any still-pending statements in the transaction are discarded.

So, if you don't want the transaction to fail, you need to provide an error callback and explicitly return false.

Unless I misinterpreted something, it sounds to me like the plugin is behaving correctly and when I added PR #170 I updated the tests for this.

@brodycj
Copy link

brodycj commented May 12, 2015

So, if you don't want the transaction to fail, you need to provide an error callback and explicitly return false.

I would agree with you according to the spec, however this Web SQL seems to behave differently (at least in Android and iOS) as shown by the old tests. I will add some more tests to show this in the next few days.

So the question becomes whether we should follow the spec more strictly at the risk of breaking apps that are working in the browser (web) SQL. My preference, at least in this case, is to match the behavior of Web SQL as we see in the browser to avoid breaking apps. @nolanlawson do you have any comments?

@nolanlawson
Copy link
Contributor

however this Web SQL seems to behave differently (at least in Android and iOS) as shown by the old tests

Hm, that's weird, never seen it behave differently myself. If you don't want the transaction to fail, you need to pass in an error callback that returns false. In fact, we rely on this behavior in the PouchDB test suite, and the test passes on PhantomJS/Android/Chrome/iOS/Safari, so that would be one way to confirm it. :)

@aarononeal
Copy link
Contributor

Prior to PR #170 the plugin would continue the transaction if a handler was either missing or returned non-true (which includes no return value) as opposed to explicit false, which I don't believe matches the spec or a desirable behavior. In that PR, I corrected the plugin to match the spec above which not only simplifies the error handling code you have to write, it allows you to detect issues you might not have been aware of otherwise, such as the root cause for the transaction failure in this bug report. If Android and iOS don't implement the logic above, I would lean towards filing bugs in WebKit to get it corrected rather than making the plugin bug compatible.

@brodycj
Copy link

brodycj commented May 26, 2015

Agreed with @aarononeal and @nolanlawson and covered in test suite.

@brodycj brodycj closed this as completed May 26, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants