]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Prevent NULLS FIRST/LAST from being used in CREATE INDEX and other statements.
authordan <dan@noemail.net>
Mon, 19 Aug 2019 17:26:32 +0000 (17:26 +0000)
committerdan <dan@noemail.net>
Mon, 19 Aug 2019 17:26:32 +0000 (17:26 +0000)
FossilOrigin-Name: bb9767a287097a615aeb4abdba689b10e1a1c36c016c8e55905b508075e62c86

manifest
manifest.uuid
src/build.c
src/expr.c
src/insert.c
src/sqliteInt.h
src/trigger.c
test/nulls1.test

index 2584ef1bad25499e72511c01104d357bc323d4c8..b8cb71e76a01aeb6337a4878f11ccbbbf3f99c56 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\stests\sto\sensure\sthat\sthis\sbranch\sreally\sdoes\sfix\sticket\s[f8a7060ece].
-D 2019-08-17T18:16:59.747
+C Prevent\sNULLS\sFIRST/LAST\sfrom\sbeing\sused\sin\sCREATE\sINDEX\sand\sother\sstatements.
+D 2019-08-19T17:26:32.202
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -467,7 +467,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
 F src/btree.c 5cf994516c1b74928b9d15971573a8bc8595e1afec129184099976da603402de
 F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
 F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
-F src/build.c 39f448776a17f202e0d205bda9e2b0bb80853503268ceb36a48ff6d0d963fd7b
+F src/build.c da5d5d82eb53cb004e9120277cfe93a9c3dd294871eae3d728ebd0faee84d969
 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
 F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
@@ -475,7 +475,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041
 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
-F src/expr.c bef29885d12c1b7ec4353fc07f61f18d044430fc4f9c1476fd5098a5834d17bd
+F src/expr.c 0a3442b0df31f1eca86b2aa3634f61bca5f1a6781f543ca9a0d87e29961f7f4f
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c 6b79f4c2447691aa9ac86e2a6a774b65f3b3dd053d4220a4893051a0de20f82e
 F src/func.c 4ee36219698d50d672a28eca4adb0fd6b92e607a1883d318315e0d2fd5044467
@@ -484,7 +484,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
-F src/insert.c c2194dd2886337b870226fcb31c13e7df8c4b5e0ea85140e510a6f1daf1ad65b
+F src/insert.c 81eec6acf4fbf0942bbab6804fe50df3e109acba40b8bbfb00fec9a14d0715a6
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 22afc33c3a61b4fd80a60a54f1882688371e6bc64685df2696b008fce65a999c
 F src/main.c 51c55eb579eac4180bfcc6242741084710911350d2cd0c3fdd0f9fde55442128
@@ -528,7 +528,7 @@ F src/shell.c.in d2465e7747a014bd48a75c1bcf648e8e6cb46832dcc6e1293c5f285bc5542e8
 F src/sqlite.h.in 5445ee2844c15bf277ebb64e910b56b0e6fb9377f184a81cd9bd78f0946be8c8
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
-F src/sqliteInt.h ed60d41dbb600515abdd5bbfd7f826f0238153d7d70fc3383f5e1179e131b3b8
+F src/sqliteInt.h 84d3b381b515acfd098152bb2c9a91fb3ea72b55e15dfc2b86c031da222a910c
 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -589,7 +589,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
 F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e
 F src/treeview.c fc8c6c0a8a26afb3a97e3f844d65403dd27cf1450baf4415034fa4ccf00c4d7e
-F src/trigger.c 2305271878e95addc1c01361e5e8e342e87cba5efefdd7d3032687e5d67e05d1
+F src/trigger.c d115eb6c1e2a22e116e0c6e34c35e5b2029238238e05b9708fe1567434da3230
 F src/update.c 3cb9150d2cf661d938e2f1b1749945f3faa767f88febdb739ab1793bbf895ff2
 F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
@@ -1182,7 +1182,7 @@ F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161
 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934
 F test/notnull.test a37b663d5bb728d66fc182016613fb8e4a0a4bbf3d75b8876a7527f7d4ed3f18
 F test/null.test 0dcce4f04284ec66108c503327ad6d224c0752b3
-F test/nulls1.test 522f0da68881b6ac616b1361fbd5a9897bd366597809495143968af743e3318c
+F test/nulls1.test 6d226787ee0d479bc009e00b7fa812fb261fbb3eab764de18ecb988f4ec69f4a
 F test/numcast.test 5d126f7f581432e86a90d1e35cac625164aec4a1
 F test/numindex1.test 20a5450d4b056e48cd5db30e659f13347a099823
 F test/offset1.test f06b83657bcf26f9ce805e67450e189e282143b2
@@ -1837,7 +1837,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b49df1fe9b7174ebc60023179e8da628c926e59df3dc01b15d4a28e17807bb97
-R 45771ddb0f2c68cf3dbfa90b9e4149c6
+P f892066425671a8a0ac923e3ad4744677f6434a66f97b91afa8141f11f179975
+R 453ca41ba88968d27d033b2c6ac5c131
 U dan
-Z 6452b2b9b9aca3f08bbef29f8e41e25a
+Z d9760a7ecfe79d11a5b817a651ccacbf
index b6a8464c5fa641f157e57ceb5b9b9047d593e526..05637d33b1674aa9e14cae9f93c419c2b68024f1 100644 (file)
@@ -1 +1 @@
-f892066425671a8a0ac923e3ad4744677f6434a66f97b91afa8141f11f179975
\ No newline at end of file
+bb9767a287097a615aeb4abdba689b10e1a1c36c016c8e55905b508075e62c86
\ No newline at end of file
index 3f9ab0b975ee5f422aa8976afd02f24a7c134e79..106b995d31ad4abfd000c7d0e9d61f35117058f9 100644 (file)
@@ -3153,6 +3153,27 @@ Index *sqlite3AllocateIndexObject(
   return p;
 }
 
+/*
+** If expression list pList contains an expression that was parsed with
+** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in
+** pParse and return non-zero. Otherwise, return zero.
+*/
+int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
+  if( pList ){
+    int i;
+    for(i=0; i<pList->nExpr; i++){
+      if( pList->a[i].bNulls ){
+        u8 sf = pList->a[i].sortFlags;
+        sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s", 
+            (sf==0 || sf==3) ? "FIRST" : "LAST"
+        );
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
 /*
 ** Create a new index for an SQL table.  pName1.pName2 is the name of the index 
 ** and pTblList is the name of the table that is to be indexed.  Both will 
@@ -3204,6 +3225,9 @@ void sqlite3CreateIndex(
   if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
     goto exit_create_index;
   }
+  if( sqlite3HasExplicitNulls(pParse, pList) ){
+    goto exit_create_index;
+  }
 
   /*
   ** Find the table that is to be indexed.  Return early if not found.
index c5072aa6150dc714b7b9de5fa5f34d87ff5b75a4..6948c5a0fe307c8c6ba7a5c9b30ae51b8832a660 100644 (file)
@@ -1653,6 +1653,7 @@ vector_append_error:
 ** Set the sort order for the last element on the given ExprList.
 */
 void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
+  struct ExprList_item *pItem;
   if( p==0 ) return;
   assert( p->nExpr>0 );
 
@@ -1666,10 +1667,18 @@ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
        || eNulls==SQLITE_SO_DESC 
   );
 
-  if( iSortOrder==SQLITE_SO_UNDEFINED ) iSortOrder = SQLITE_SO_ASC;
-  p->a[p->nExpr-1].sortFlags = (u8)iSortOrder;
-  if( eNulls!=SQLITE_SO_UNDEFINED && iSortOrder!=eNulls ){
-    p->a[p->nExpr-1].sortFlags |= KEYINFO_ORDER_BIGNULL;
+  pItem = &p->a[p->nExpr-1];
+  assert( pItem->bNulls==0 );
+  if( iSortOrder==SQLITE_SO_UNDEFINED ){
+    iSortOrder = SQLITE_SO_ASC;
+  }
+  pItem->sortFlags = (u8)iSortOrder;
+
+  if( eNulls!=SQLITE_SO_UNDEFINED ){
+    pItem->bNulls = 1;
+    if( iSortOrder!=eNulls ){
+      pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
+    }
   }
 }
 
index 53d7e89b2ab2d6a0d6eaa7c7ccbda4b3d8259c5d..04d3d580f5d1c246651b7eaf34eedc23c7558a69 100644 (file)
@@ -833,6 +833,9 @@ void sqlite3Insert(
               pTab->zName);
       goto insert_cleanup;
     }
+    if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
+      goto insert_cleanup;
+    }
     pTabList->a[0].iCursor = iDataCur;
     pUpsert->pUpsertSrc = pTabList;
     pUpsert->regData = regData;
index c47cc6ffc7304baa4f45007a93dd2f9f84c360e1..b777409179f61ac7cab1b2a3d45778c0f08c4dd2 100644 (file)
@@ -2605,11 +2605,12 @@ struct ExprList {
     Expr *pExpr;            /* The parse tree for this expression */
     char *zName;            /* Token associated with this expression */
     char *zSpan;            /* Original text of the expression */
-    u8 sortFlags;           /* 1 for DESC or 0 for ASC */
+    u8 sortFlags;           /* Mask of KEYINFO_ORDER_* flags */
     unsigned done :1;       /* A flag to indicate when processing is finished */
     unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
     unsigned reusable :1;   /* Constant expression is reusable */
     unsigned bSorterRef :1; /* Defer evaluation until after sorting */
+    unsigned bNulls: 1;     /* True if explicit "NULLS FIRST/LAST" */
     union {
       struct {
         u16 iOrderByCol;      /* For ORDER BY, column number in result set */
@@ -4366,6 +4367,7 @@ void sqlite3KeyInfoUnref(KeyInfo*);
 KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
 KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
 KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
+int sqlite3HasExplicitNulls(Parse*, ExprList*);
 
 #ifdef SQLITE_DEBUG
 int sqlite3KeyInfoIsWriteable(KeyInfo*);
index 989df9678aabf50dfacc8d70bb454e0c76e50ae1..84f80c23ee8f940cf5847e0545fdcda7cc92ac31 100644 (file)
@@ -463,6 +463,9 @@ TriggerStep *sqlite3TriggerInsertStep(
     pTriggerStep->pIdList = pColumn;
     pTriggerStep->pUpsert = pUpsert;
     pTriggerStep->orconf = orconf;
+    if( pUpsert ){
+      sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget);
+    }
   }else{
     testcase( pColumn );
     sqlite3IdListDelete(db, pColumn);
index 866ed2b296c8e5ad28acc428d0e34fbd3e7e3a15..dc7fb6e86bd288709df661bf7901407ae908bf52 100644 (file)
@@ -83,5 +83,43 @@ do_execsql_test 2.2 {
   1 1 1
 }
 
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 3.0 {
+  CREATE TABLE t1(a, b, c, d, UNIQUE (b));
+}
+foreach {tn sql err}  {
+  1 { CREATE INDEX i1 ON t1(a ASC NULLS LAST) }           LAST
+  2 { CREATE INDEX i1 ON t1(a ASC NULLS FIRST) }          FIRST
+  3 { CREATE INDEX i1 ON t1(a, b ASC NULLS LAST) }        LAST
+  4 { CREATE INDEX i1 ON t1(a, b ASC NULLS FIRST) }       FIRST
+  5 { CREATE INDEX i1 ON t1(a DESC NULLS LAST) }          LAST
+  6 { CREATE INDEX i1 ON t1(a DESC NULLS FIRST) }         FIRST
+  7 { CREATE INDEX i1 ON t1(a, b DESC NULLS LAST) }       LAST
+  8 { CREATE INDEX i1 ON t1(a, b DESC NULLS FIRST) }      FIRST
+  9  { CREATE TABLE t2(a, b, PRIMARY KEY(a DESC, b NULLS FIRST)) } FIRST
+  10 { CREATE TABLE t2(a, b, UNIQUE(a DESC NULLS FIRST, b)) }      FIRST
+  11 { INSERT INTO t1 VALUES(1, 2, 3, 4)
+          ON CONFLICT (b DESC NULLS LAST) DO UPDATE SET a = a+1 } LAST
+  12 {
+    CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
+      INSERT INTO t1 VALUES(1, 2, 3, 4)
+      ON CONFLICT (b DESC NULLS FIRST) DO UPDATE SET a = a+1;
+    END
+  } FIRST
+} {
+  do_catchsql_test 3.1.$tn $sql "1 {unsupported use of NULLS $err}"
+}
+
+do_execsql_test 3.2 {
+  CREATE TABLE first(nulls, last);
+  INSERT INTO first(last, nulls) VALUES(100,200), (300,400), (200,300);
+  SELECT * FROM first ORDER BY nulls;
+} {
+  200 100
+  300 200
+  400 300
+}
+
 
 finish_test