David wrote:
> Simon L wrote 2011-10-25 06:20:
>> To reproduce this problem, enter the following 5 SQL statements at the
>> SQLite command line.
>>
>> create table X(id INTEGER primary key ON CONFLICT REPLACE);
>> create table Y(id INTEGER primary key ON CONFLICT REPLACE);
>> insert into X values (1);
>> insert into Y select * from X;
>> insert into Y select * from X;
>>
>>
>> When I tried to run the last SQL statement twice,  SQLite produced the
>> following error message.
>> Error: PRIMARY KEY must be unique
>>
>>
>> Is this a bug? Please advise. Thank you.
>> _______________________________________________
>> sqlite-users mailing list
>> sqlite-users@sqlite.org
>> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
> 
> This certainly looks like a bug. I got a constraint failure when I tried
> it in sqlite 3.7.8.
> 
> But it works fine when you state the column name explicitly in the
> select clause.
> 
> Like this:
> 
> create table X(id INTEGER primary key ON CONFLICT REPLACE);
> create table Y(id INTEGER primary key ON CONFLICT REPLACE);
> insert into X values (1);
> insert into Y select id from X;
> insert into Y select id from X;
>
> I recall the "INSERT INTO ... SELECT * ..." had a bug related to foreign
> key checks,
> which was reported on the mailing list earlier this year:
> 
> http://www.sqlite.org/src/tktview?name=6284df89de
> 
> Hopefully, a member of the sqlite dev team will acknowledge this bug soon.

Thanks for pointer; root cause, indeed, transfer optimization (it ignores table
INTEGER PRIMARY KEY's ON CONFLICT clause, fix was easy, patch below (use table's
ON CONFLICT clause by default; falls back to regular transfer if destination
table is not empty and we cannot handle ON CONFLICT resolution);

Disclaimer: /me is not sqlite dev team member, review carefully, use with care.

The author or authors of this code dedicate any and all copyright interest
in this code to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and successors.
We intend this dedication to be an overt act of relinquishment in perpetuity
of all present and future rights to this code under copyright law.

Signed-off-by: Yuriy M. Kaminskiy <yum...@gmail.com>

Index: sqlite3-3.7.8/src/insert.c
===================================================================
--- sqlite3-3.7.8.orig/src/insert.c     2011-10-25 15:20:26.000000000 +0400
+++ sqlite3-3.7.8/src/insert.c  2011-10-25 15:54:54.000000000 +0400
@@ -1626,6 +1626,7 @@ static int xferOptimization(
   int regAutoinc;                  /* Memory register used by AUTOINC */
   int destHasUniqueIdx = 0;        /* True if pDest has a UNIQUE index */
   int regData, regRowid;           /* Registers holding data and rowid */
+  int keyConf = pDest->iPKey>=0 ? pDest->keyConf : OE_Default;

   if( pSelect==0 ){
     return 0;   /* Must be of the form  INSERT INTO ... SELECT ... */
@@ -1639,7 +1640,22 @@ static int xferOptimization(
   }
 #endif
   if( onError==OE_Default ){
-    onError = OE_Abort;
+    if( keyConf==OE_Abort || keyConf==OE_Rollback )
+      /* can be handled - take ON CONFLICT from table declaration */
+      onError = keyConf;
+    else {
+      if( keyConf==OE_Default )
+        keyConf = OE_Abort;
+      else {
+        /* Not default and cannot be handled;
+        ** fallback to regular transfer if destination is not empty (below)
+        */
+      }
+      onError = OE_Abort;
+    }
+  } else {
+    /* statement ON CONFLICT overrides table ON CONFLICT */
+    keyConf = onError;
   }
   if( onError!=OE_Abort && onError!=OE_Rollback ){
     return 0;   /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */
@@ -1766,7 +1782,8 @@ static int xferOptimization(
   iDest = pParse->nTab++;
   regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
   sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
-  if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
+  if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ||
+      (/*pDest->iPKey>=0 && */keyConf!=onError) ) {
     /* If tables do not have an INTEGER PRIMARY KEY and there
     ** are indices to be copied and the destination is not empty,
     ** we have to disallow the transfer optimization because the
@@ -1776,6 +1793,9 @@ static int xferOptimization(
     ** we also disallow the transfer optimization because we cannot
     ** insure that all entries in the union of DEST and SRC will be
     ** unique.
+    **
+    ** Or if destination INTEGER PRIMARY KEY has ON CONFLICT clause
+    ** that we cannot handle and destination is not empty.
     */
     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0);
     emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);

_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to