1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Make the distinction between truly deterministic functions and date/time

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
This commit is contained in:
drh
2015-08-31 17:34:41 +00:00
parent 47991425cb
commit 1d85e405e6
6 changed files with 160 additions and 43 deletions

View File

@@ -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

View File

@@ -1 +1 @@
f8893696387cba9d293a05a68dc38228077b3dc5
c77554b5c42327106a7b90334e9cc3c07b007c76

View 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),

View 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);
}
}

View 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 */

View 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