Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Always disallow the use of non-deterministic functions in CHECK constraints, even date/time functions that use the 'now' or similar keywords. Provide improved error messages when this requirement is not met. Ticket [830277d9db6c3ba1] |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
2978b65ebe25eeabe543b67cb266308c |
User & Date: | drh 2019-10-30 18:50:08.069 |
Context
2019-10-31
| ||
12:30 | Enhance the TreeView logic to show information about Expr.op2 for FUNCTION and COLUMN nodes. (check-in: aceeaf9e28 user: drh tags: trunk) | |
2019-10-30
| ||
18:50 | Always disallow the use of non-deterministic functions in CHECK constraints, even date/time functions that use the 'now' or similar keywords. Provide improved error messages when this requirement is not met. Ticket [830277d9db6c3ba1] (check-in: 2978b65ebe user: drh tags: trunk) | |
16:29 | Simplify the bytecode generation for SQL function calls such that the OP_Function or OP_PureFunc opcodes are coded directly, rather than using the intermediate OP_Function0 or OP_PureFunc0 - opcodes that are now removed. (check-in: 84e02d773d user: drh tags: trunk) | |
Changes
Changes to ext/misc/totype.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | > | | > | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "tointeger", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, tointegerFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0, torealFunc, 0, 0); } return rc; } |
Changes to src/expr.c.
︙ | ︙ | |||
4029 4030 4031 4032 4033 4034 4035 | }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } }else #endif { sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, | | | 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 | }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } }else #endif { sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, pDef, pExpr->op2); } if( nFarg && constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); } return target; } #ifndef SQLITE_OMIT_SUBQUERY |
︙ | ︙ | |||
5024 5025 5026 5027 5028 5029 5030 | if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE && (combinedFlags & EP_Reduced)==0 ){ if( pA->iColumn!=pB->iColumn ) return 2; | | | 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 | if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE && (combinedFlags & EP_Reduced)==0 ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->op2!=pB->op2 && (pA->op!=TK_FUNCTION || iTab<0) ) return 2; if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){ return 2; } } } return 0; } |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
811 812 813 814 815 816 817 | return WRC_Prune; } } #endif if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered | | > | > > | | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | return WRC_Prune; } } #endif if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered ** constant because they are constant for the duration of one query. ** This allows them to be factored out of inner loops. */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ /* Date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", NC_SelfRef); }else{ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ pExpr->op2 = pNC->ncFlags & NC_SelfRef; } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 && sqlite3Config.bInternalFunctions==0 ){ /* Internal-use-only functions are disallowed unless the ** SQL is being compiled using sqlite3NestedParse() */ |
︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 | sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** | > > | | | | | | 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 | sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** ** "type" flag ** ------------ ** (1) CHECK constraints NC_IsCheck ** (2) WHERE clauses on partial indices NC_PartIdx ** (3) Expressions in indexes on expressions NC_IdxExpr ** (4) Expression arguments to VACUUM INTO. 0 ** (5) GENERATED ALWAYS as expressions NC_GenCol ** ** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN ** nodes of the expression is set to -1 and the Expr.iColumn value is ** set to the column number. In case (4), TK_COLUMN nodes cause an error. ** ** Any errors cause an error message to be set in pParse. */ |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 | ** are contained within the same memory allocation. Note, however, that ** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affExpr; /* affinity, or RAISE type */ u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no | > > > > | 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 | ** are contained within the same memory allocation. Note, however, that ** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affExpr; /* affinity, or RAISE type */ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */ u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no |
︙ | ︙ | |||
2521 2522 2523 2524 2525 2526 2527 | ** TK_SELECT_COLUMN: Number of columns on the LHS ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ | < < < | 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 | ** TK_SELECT_COLUMN: Number of columns on the LHS ** TK_SELECT: 1st register of result vector */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ union { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ |
︙ | ︙ | |||
2836 2837 2838 2839 2840 2841 2842 | ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX ** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */ | | > | | 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 | ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX ** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */ #define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */ #define NC_HasAgg 0x00010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */ #define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */ #define NC_VarSelect 0x00040 /* A correlated subquery has been seen */ #define NC_UEList 0x00080 /* True if uNC.pEList is used */ #define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */ #define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */ #define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x02000 /* True if a function or subquery seen */ #define NC_AllowWin 0x04000 /* Window functions are allowed here */ #define NC_HasWin 0x08000 /* One or more window functions seen */ #define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ #define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */ /* ** An instance of the following object describes a single ON CONFLICT ** clause in an upsert. ** ** The pUpsertTarget field is only set if the ON CONFLICT clause includes ** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
361 362 363 364 365 366 367 | if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); return 0; } pCtx->pOut = 0; pCtx->pFunc = (FuncDef*)pFunc; | | > | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | if( pCtx==0 ){ assert( pParse->db->mallocFailed ); freeEphemeralFunction(pParse->db, (FuncDef*)pFunc); return 0; } pCtx->pOut = 0; pCtx->pFunc = (FuncDef*)pFunc; pCtx->pVdbe = 0; pCtx->isError = 0; pCtx->argc = nArg; addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function, p1, p2, p3, (char*)pCtx, P4_FUNCCTX); sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef); pCtx->iOp = addr; return addr; } /* ** Add an opcode that includes the p4 value with a P4_INT64 or ** P4_REAL type. |
︙ | ︙ | |||
4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 | ** ** OP_PureFunc means that the function must be deterministic, and should ** throw an error if it is given inputs that would make it non-deterministic. ** This routine is invoked by date/time functions that use non-deterministic ** features such as 'now'. */ int sqlite3NotPureFunc(sqlite3_context *pCtx){ #ifdef SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 1; #endif | > > | < > | > > > > > > > | | < < < < < | 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 | ** ** OP_PureFunc means that the function must be deterministic, and should ** throw an error if it is given inputs that would make it non-deterministic. ** This routine is invoked by date/time functions that use non-deterministic ** features such as 'now'. */ int sqlite3NotPureFunc(sqlite3_context *pCtx){ const VdbeOp *pOp; #ifdef SQLITE_ENABLE_STAT4 if( pCtx->pVdbe==0 ) return 1; #endif pOp = pCtx->pVdbe->aOp + pCtx->iOp; if( pOp->opcode==OP_PureFunc ){ const char *zContext; char *zMsg; if( pOp->p5 & NC_IsCheck ){ zContext = "a CHECK constraint"; }else if( pOp->p5 & NC_GenCol ){ zContext = "a generated column"; }else{ zContext = "an index"; } zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s", pCtx->pFunc->zName, zContext); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); return 0; } return 1; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* |
︙ | ︙ |
Changes to test/check.test.
︙ | ︙ | |||
438 439 440 441 442 443 444 | # If a connection opens a database that contains a CHECK constraint that # uses an unknown UDF, the schema should not be considered malformed. # Attempting to modify the table should fail (since the CHECK constraint # cannot be tested). # reset_db proc myfunc {x} {expr $x < 10} | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | # If a connection opens a database that contains a CHECK constraint that # uses an unknown UDF, the schema should not be considered malformed. # Attempting to modify the table should fail (since the CHECK constraint # cannot be tested). # reset_db proc myfunc {x} {expr $x < 10} db func myfunc -deterministic myfunc do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) } do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) } do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } \ {1 {CHECK constraint failed: t6}} do_test 7.4 { |
︙ | ︙ |
Changes to test/date2.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | do_execsql_test date2-100 { CREATE TABLE t1(x, y, CHECK( date(x) BETWEEN '2017-07-01' AND '2017-07-31' )); INSERT INTO t1(x,y) VALUES('2017-07-20','one'); } {} do_catchsql_test date2-110 { INSERT INTO t1(x,y) VALUES('now','two'); | | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | do_execsql_test date2-100 { CREATE TABLE t1(x, y, CHECK( date(x) BETWEEN '2017-07-01' AND '2017-07-31' )); INSERT INTO t1(x,y) VALUES('2017-07-20','one'); } {} do_catchsql_test date2-110 { INSERT INTO t1(x,y) VALUES('now','two'); } {1 {non-deterministic use of date() in a CHECK constraint}} do_execsql_test date2-120 { SELECT * FROM t1; } {2017-07-20 one} do_catchsql_test date2-130 { INSERT INTO t1(x,y) VALUES('2017-08-01','two'); } {1 {CHECK constraint failed: t1}} do_execsql_test date2-200 { CREATE TABLE t2(x,y); INSERT INTO t2(x,y) VALUES(1, '2017-07-20'), (2, 'xyzzy'); CREATE INDEX t2y ON t2(date(y)); } do_catchsql_test date2-210 { INSERT INTO t2(x,y) VALUES(3, 'now'); } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-220 { SELECT x, y FROM t2 ORDER BY x; } {1 2017-07-20 2 xyzzy} do_execsql_test date2-300 { CREATE TABLE t3(a INTEGER PRIMARY KEY,b); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t3(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t3 SET b='now' WHERE a=500; } do_catchsql_test date2-310 { CREATE INDEX t3b1 ON t3(datetime(b)); } {1 {non-deterministic use of datetime() in an index}} do_catchsql_test date2-320 { CREATE INDEX t3b1 ON t3(datetime(b)) WHERE typeof(b)='real'; } {0 {}} do_execsql_test date2-330 { EXPLAIN QUERY PLAN SELECT a FROM t3 WHERE typeof(b)='real' |
︙ | ︙ | |||
80 81 82 83 84 85 86 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t4(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t4 SET b='now' WHERE a=500; } do_catchsql_test date2-410 { CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000) INSERT INTO t4(a,b) SELECT x, julianday('2017-07-01')+x FROM c; UPDATE t4 SET b='now' WHERE a=500; } do_catchsql_test date2-410 { CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-420 { DELETE FROM t4 WHERE a=500; CREATE INDEX t4b1 ON t4(b) WHERE date(b) BETWEEN '2017-06-01' AND '2017-08-31'; } do_catchsql_test date2-430 { INSERT INTO t4(a,b) VALUES(9999,'now'); } {1 {non-deterministic use of date() in an index}} do_execsql_test date2-500 { CREATE TABLE mods(x); INSERT INTO mods(x) VALUES ('+10 days'), ('-10 days'), ('+10 hours'), |
︙ | ︙ | |||
117 118 119 120 121 122 123 | CREATE TABLE t5(y,m); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) INSERT INTO t5(y,m) SELECT julianday('2017-07-01')+c.x, mods.x FROM c, mods; CREATE INDEX t5x1 on t5(y) WHERE datetime(y,m) IS NOT NULL; } do_catchsql_test date2-510 { INSERT INTO t5(y,m) VALUES('2017-07-20','localtime'); | | | > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | CREATE TABLE t5(y,m); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) INSERT INTO t5(y,m) SELECT julianday('2017-07-01')+c.x, mods.x FROM c, mods; CREATE INDEX t5x1 on t5(y) WHERE datetime(y,m) IS NOT NULL; } do_catchsql_test date2-510 { INSERT INTO t5(y,m) VALUES('2017-07-20','localtime'); } {1 {non-deterministic use of datetime() in an index}} do_catchsql_test date2-520 { INSERT INTO t5(y,m) VALUES('2017-07-20','utc'); } {1 {non-deterministic use of datetime() in an index}} # 2019-10-30 Ticket 830277d9db6c3ba1 # do_catchsql_test date2-600 { CREATE TABLE t600(a REAL CHECK( a<julianday('now') )); INSERT INTO t600(a) VALUES(1.0); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-601 { CREATE TABLE t601(a REAL, b TEXT, CHECK( a<julianday(b) )); INSERT INTO t601(a,b) VALUES(1.0, '1970-01-01'); } {0 {}} do_catchsql_test date2-602 { INSERT INTO t601(a,b) VALUES(1e100, '1970-01-01'); } {1 {CHECK constraint failed: t601}} do_catchsql_test date2-603 { INSERT INTO t601(a,b) VALUES(10, 'now'); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-604 { INSERT INTO t600(a) VALUES(julianday('now')+10); } {1 {non-deterministic use of julianday() in a CHECK constraint}} do_catchsql_test date2-610 { CREATE TABLE t610(a,b); CREATE INDEX t610x1 ON t610(julianday('now')+b); INSERT INTO t610(a,b) VALUES(123,456); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test date2-611 { CREATE TABLE t611(a,b); CREATE INDEX t611x1 ON t611(julianday(a)+b); INSERT INTO t611(a,b) VALUES('1970-01-01',10.0); } {0 {}} do_catchsql_test date2-612 { INSERT INTO t611(a,b) VALUES('now',10.0); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test date3-620 { CREATE TABLE t620(a, b AS (a+julianday('now'))); INSERT INTO t620 VALUES(10); } {1 {non-deterministic use of julianday() in a generated column}} finish_test |
Changes to test/indexexpr1.test.
︙ | ︙ | |||
182 183 184 185 186 187 188 | do_catchsql_test indexexpr1-300 { CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(1,2,3); 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(julianday('now',a)); | | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | do_catchsql_test indexexpr1-300 { CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(1,2,3); 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(julianday('now',a)); } {1 {non-deterministic use of julianday() in an index}} do_catchsql_test indexexpr1-310 { CREATE INDEX t2x2 ON t2(a,b+(SELECT 15)); } {1 {subqueries prohibited in index expressions}} do_catchsql_test indexexpr1-320 { CREATE TABLE e1(x,y,UNIQUE(y,substr(x,1,5))); } {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}} do_catchsql_test indexexpr1-330 { |
︙ | ︙ |