]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make the distinction between truly deterministic functions and date/time
authordrh <drh@noemail.net>
Mon, 31 Aug 2015 17:34:41 +0000 (17:34 +0000)
committerdrh <drh@noemail.net>
Mon, 31 Aug 2015 17:34:41 +0000 (17:34 +0000)
functions which only return the same answer for a single query.  Only truly
deterministic functions are allowed in indexes.  Add new expression index
test cases.

FossilOrigin-Name: c77554b5c42327106a7b90334e9cc3c07b007c76

manifest
manifest.uuid
src/date.c
src/resolve.c
src/sqliteInt.h
test/indexexpr1.test

index 64b3dc444a7180f8f9d005e5730fe45931d57f7c..bcc1d9de6b4bfa4a001829bab5396075c0e013e3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improved\sanalysis\sand\susage\sof\sindexed\sexpressions\sin\sthe\squery\splanner.
-D 2015-08-31T15:58:06.350
+C Make\sthe\sdistinction\sbetween\struly\sdeterministic\sfunctions\sand\sdate/time\nfunctions\swhich\sonly\sreturn\sthe\ssame\sanswer\sfor\sa\ssingle\squery.\s\sOnly\struly\ndeterministic\sfunctions\sare\sallowed\sin\sindexes.\s\sAdd\snew\sexpression\sindex\ntest\scases.
+D 2015-08-31T17:34:41.308
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -286,7 +286,7 @@ F src/build.c e0902658fc86dbd60a5c6772ca45429c69ee81fe
 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
-F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58
+F src/date.c fb1c99172017dcc8e237339132c91a21a0788584
 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
 F src/delete.c 224e5c9a0eae7fbdd3b461ca971465c992851354
 F src/expr.c cf0c5ef6467d3eb65e3ff5c88eb2f602ba3b5163
@@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a
 F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc
 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
-F src/resolve.c e6dc5a5490cf93afc1cc2cb58280c98da56acb3c
+F src/resolve.c 3ec6456a534bcbf0f3fc11ad83c6208301db60a2
 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
 F src/select.c b52c80f2b1bdb62491f9ce40eea0c5f80c78d105
 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42
 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00
 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
 F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413
-F src/sqliteInt.h 340fc115a707838ad365b52057f126b143f6aa60
+F src/sqliteInt.h 332ae4f753d91c92421a2c4227c195298d5b154c
 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
@@ -780,7 +780,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a
 F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
 F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353
-F test/indexexpr1.test 36b7aab1fdb03710b99ee876ff764b92c7b96e3e
+F test/indexexpr1.test 1e57b4bb93b65a451803e7547a51f685af1c35db
 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
@@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 7bde6d4d8cf05e1beb9bdf20b85760dc3e7a76c9
-R b7744e5a00368fcccd1913a83a0521e8
+P f8893696387cba9d293a05a68dc38228077b3dc5
+R 73b6719fd207957d3d30c3e1b6c218bc
 U drh
-Z 32945199df036dc2360847bdab3537ac
+Z fe2263cb4a747333f78b4cc6eb661f66
index 327673b19f75194e2a200d93da572cb19d96c845..3dc8f017b90020900d5cb00bca1f21125e81f3e2 100644 (file)
@@ -1 +1 @@
-f8893696387cba9d293a05a68dc38228077b3dc5
\ No newline at end of file
+c77554b5c42327106a7b90334e9cc3c07b007c76
\ No newline at end of file
index 6b11d9904aa220836510e6e31c037455dfa61ecf..8a66eae900c68539de37c1f5de298abab58e1a38 100644 (file)
@@ -1115,14 +1115,14 @@ static void currentTimeFunc(
 void sqlite3RegisterDateTimeFunctions(void){
   static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
 #ifndef SQLITE_OMIT_DATETIME_FUNCS
-    FUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
-    FUNCTION(date,             -1, 0, 0, dateFunc      ),
-    FUNCTION(time,             -1, 0, 0, timeFunc      ),
-    FUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
-    FUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
-    FUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
-    FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
-    FUNCTION(current_date,      0, 0, 0, cdateFunc     ),
+    DFUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
+    DFUNCTION(date,             -1, 0, 0, dateFunc      ),
+    DFUNCTION(time,             -1, 0, 0, timeFunc      ),
+    DFUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
+    DFUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
+    DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
+    DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
+    DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
 #else
     STR_FUNCTION(current_time,      0, "%H:%M:%S",          0, currentTimeFunc),
     STR_FUNCTION(current_date,      0, "%Y-%m-%d",          0, currentTimeFunc),
index eb43396454a3bfa0f130c7ce9add02acc98d33ba..0b8dde7cc6e2f29a59f7e1e310436eed1de0aa3c 100644 (file)
@@ -732,9 +732,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
           return WRC_Prune;
         }
 #endif
-        if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
+        if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_DATETIME) ){
+          /* For the purposes of the EP_ConstFunc flag, date and time
+          ** functions are considered constant because the the time does
+          ** not change for the duration of a query. */
           ExprSetProperty(pExpr,EP_ConstFunc);
-        }else{
+        }
+        if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
+          /* DATETIME functions are considered non-deterministic because of
+          ** the 'now' capability */
           notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr, 0);
         }
       }
index 69f98da26dfb7f835f98626acc37f9d874aee723..613f351aa57b41eac715f224fb43364a389eb83b 100644 (file)
@@ -1384,18 +1384,19 @@ struct FuncDestructor {
 ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  There
 ** are assert() statements in the code to verify this.
 */
-#define SQLITE_FUNC_ENCMASK  0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
-#define SQLITE_FUNC_LIKE     0x004 /* Candidate for the LIKE optimization */
-#define SQLITE_FUNC_CASE     0x008 /* Case-sensitive LIKE-type function */
-#define SQLITE_FUNC_EPHEM    0x010 /* Ephemeral.  Delete with VDBE */
-#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */
-#define SQLITE_FUNC_LENGTH   0x040 /* Built-in length() function */
-#define SQLITE_FUNC_TYPEOF   0x080 /* Built-in typeof() function */
-#define SQLITE_FUNC_COUNT    0x100 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
-#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
-#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
-#define SQLITE_FUNC_MINMAX  0x1000 /* True for min() and max() aggregates */
+#define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
+#define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
+#define SQLITE_FUNC_CASE     0x0008 /* Case-sensitive LIKE-type function */
+#define SQLITE_FUNC_EPHEM    0x0010 /* Ephemeral.  Delete with VDBE */
+#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
+#define SQLITE_FUNC_LENGTH   0x0040 /* Built-in length() function */
+#define SQLITE_FUNC_TYPEOF   0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_COUNT    0x0100 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
+#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
+#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
+#define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
+#define SQLITE_FUNC_DATETIME 0x2000 /* Function returns a date and/or time */
 
 /*
 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1411,6 +1412,10 @@ struct FuncDestructor {
 **   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
 **     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
 **
+**   DFUNCTION(zName, nArg, iArg, bNC, xFunc)
+**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
+**     adds the SQLITE_FUNC_DATETIME flag.  Used for date & time functions.
+**
 **   AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
 **     Used to create an aggregate function definition implemented by
 **     the C functions xStep and xFinal. The first four parameters
@@ -1431,6 +1436,9 @@ struct FuncDestructor {
 #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
+#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
+  {nArg, SQLITE_FUNC_DATETIME|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
 #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
   {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
    SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
@@ -2121,7 +2129,7 @@ struct Expr {
 #define EP_MemToken  0x010000 /* Need to sqlite3DbFree() Expr.zToken */
 #define EP_NoReduce  0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
 #define EP_Unlikely  0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
+#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _DATETIME function */
 #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
 #define EP_Subquery  0x200000 /* Tree contains a TK_SELECT operator */
 
index c912226ce5d830bc84abc97bc623bf232f25c54c..0b3e7c66039eff7f0e7f19772906efc0368677c0 100644 (file)
@@ -18,28 +18,131 @@ source $testdir/tester.tcl
 do_execsql_test indexexpr1-100 {
   CREATE TABLE t1(a,b,c);
   INSERT INTO t1(a,b,c)
-  VALUES('In the beginning was the Word',1,1),
-        ('and the Word was with God',1,2),
-        ('and the Word was God',1,3),
-        ('The same was in the beginning with God',2,1),
-        ('All things were made by him',3,1),
-        ('and without him was not any thing made that was made',3,2);
+  VALUES('In_the_beginning_was_the_Word',1,1),
+        ('and_the_Word_was_with_God',1,2),
+        ('and_the_Word_was_God',1,3),
+        ('The_same_was_in_the_beginning_with_God',2,1),
+        ('All_things_were_made_by_him',3,1),
+        ('and_without_him_was_not_any_thing_made_that_was_made',3,2);
   CREATE INDEX t1a1 ON t1(substr(a,1,12));
 } {}
 do_execsql_test indexexpr1-110 {
-  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c;
+  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
 } {1 2 | 1 3 |}
 do_execsql_test indexexpr1-110eqp {
   EXPLAIN QUERY PLAN
-  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c;
+  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
 } {/USING INDEX t1a1/}
 do_execsql_test indexexpr1-120 {
-  SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c;
+  SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
 } {1 2 | 1 3 |}
 do_execsql_test indexexpr1-120eqp {
   EXPLAIN QUERY PLAN
-  SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c;
+  SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
 } {/USING INDEX t1a1/}
 
+do_execsql_test indexexpr1-130 {
+  CREATE INDEX t1ba ON t1(b,substr(a,2,3),c);
+  SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
+} {2 3}
+do_execsql_test indexexpr1-130eqp {
+  EXPLAIN QUERY PLAN
+  SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
+} {/USING INDEX t1ba/}
+
+do_execsql_test indexexpr1-140 {
+  SELECT rowid, substr(a,b,3), '|' FROM t1 ORDER BY 2;
+} {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |}
+do_execsql_test indexexpr1-141 {
+  CREATE INDEX t1abx ON t1(substr(a,b,3));
+  SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid;
+} {1 2 3}
+do_execsql_test indexexpr1-141eqp {
+  EXPLAIN QUERY PLAN
+  SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid;
+} {/USING INDEX t1abx/}
+do_execsql_test indexexpr1-142 {
+  SELECT rowid FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +rowid;
+} {1 2 3}
+do_execsql_test indexexpr1-150 {
+  SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
+   ORDER BY +rowid;
+} {2 3 5}
+do_execsql_test indexexpr1-150eqp {
+  EXPLAIN QUERY PLAN
+  SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
+   ORDER BY +rowid;
+} {/USING INDEX t1abx/}
+
+do_execsql_test indexexpr1-200 {
+  DROP TABLE t1;
+  CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID;
+  INSERT INTO t1(id,a,b,c)
+  VALUES(1,'In_the_beginning_was_the_Word',1,1),
+        (2,'and_the_Word_was_with_God',1,2),
+        (3,'and_the_Word_was_God',1,3),
+        (4,'The_same_was_in_the_beginning_with_God',2,1),
+        (5,'All_things_were_made_by_him',3,1),
+        (6,'and_without_him_was_not_any_thing_made_that_was_made',3,2);
+  CREATE INDEX t1a1 ON t1(substr(a,1,12));
+} {}
+do_execsql_test indexexpr1-210 {
+  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
+} {1 2 | 1 3 |}
+do_execsql_test indexexpr1-210eqp {
+  EXPLAIN QUERY PLAN
+  SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
+} {/USING INDEX t1a1/}
+do_execsql_test indexexpr1-220 {
+  SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
+} {1 2 | 1 3 |}
+do_execsql_test indexexpr1-220eqp {
+  EXPLAIN QUERY PLAN
+  SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
+} {/USING INDEX t1a1/}
+
+do_execsql_test indexexpr1-230 {
+  CREATE INDEX t1ba ON t1(b,substr(a,2,3),c);
+  SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
+} {2 3}
+do_execsql_test indexexpr1-230eqp {
+  EXPLAIN QUERY PLAN
+  SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
+} {/USING INDEX t1ba/}
+
+do_execsql_test indexexpr1-240 {
+  SELECT id, substr(a,b,3), '|' FROM t1 ORDER BY 2;
+} {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |}
+do_execsql_test indexexpr1-241 {
+  CREATE INDEX t1abx ON t1(substr(a,b,3));
+  SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id;
+} {1 2 3}
+do_execsql_test indexexpr1-241eqp {
+  EXPLAIN QUERY PLAN
+  SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id;
+} {/USING INDEX t1abx/}
+do_execsql_test indexexpr1-242 {
+  SELECT id FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +id;
+} {1 2 3}
+do_execsql_test indexexpr1-250 {
+  SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
+   ORDER BY +id;
+} {2 3 5}
+do_execsql_test indexexpr1-250eqp {
+  EXPLAIN QUERY PLAN
+  SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
+   ORDER BY +id;
+} {/USING INDEX t1abx/}
+
+do_catchsql_test indexexpr1-300 {
+  CREATE TABLE t2(a,b,c);
+  CREATE INDEX t2x1 ON t2(a,b+random());
+} {1 {non-deterministic functions prohibited in index expressions}}
+do_catchsql_test indexexpr1-301 {
+  CREATE INDEX t2x1 ON t2(a+julianday('now'));
+} {1 {non-deterministic functions prohibited in index expressions}}
+do_catchsql_test indexexpr1-310 {
+  CREATE INDEX t2x2 ON t2(a,b+(SELECT 15));
+} {1 {subqueries prohibited in index expressions}}
 
 finish_test