Skip to content

Commit 9244748

Browse files
author
D. Richard Hipp
committed
Assume that an SQL function is able to return a subtype if any of its
arguments are SQL functions that are able to return subtypes. This closes a corner-case hole in the patch at [ba789a7804ab96d8].
2 parents dd5e3d0 + 795d449 commit 9244748

File tree

2 files changed

+106
-10
lines changed

2 files changed

+106
-10
lines changed

src/where.c

+54-10
Original file line numberDiff line numberDiff line change
@@ -5989,6 +5989,58 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
59895989
}
59905990
}
59915991

5992+
/*
5993+
** Expression Node callback for sqlite3ExprCanReturnSubtype().
5994+
**
5995+
** Only a function call is able to return a subtype. So if the node
5996+
** is not a function call, return WRC_Prune immediately.
5997+
**
5998+
** A function call is able to return a subtype if it has the
5999+
** SQLITE_RESULT_SUBTYPE property.
6000+
**
6001+
** Assume that every function is able to pass-through a subtype from
6002+
** one of its argument (using sqlite3_result_value()). Most functions
6003+
** are not this way, but we don't have a mechanism to distinguish those
6004+
** that are from those that are not, so assume they all work this way.
6005+
** That means that if one of its arguments is another function and that
6006+
** other function is able to return a subtype, then this function is
6007+
** able to return a subtype.
6008+
*/
6009+
static int exprNodeCanReturnSubtype(Walker *pWalker, Expr *pExpr){
6010+
int n;
6011+
FuncDef *pDef;
6012+
sqlite3 *db;
6013+
if( pExpr->op!=TK_FUNCTION ){
6014+
return WRC_Prune;
6015+
}
6016+
assert( ExprUseXList(pExpr) );
6017+
db = pWalker->pParse->db;
6018+
n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
6019+
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
6020+
if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
6021+
pWalker->eCode = 1;
6022+
return WRC_Prune;
6023+
}
6024+
return WRC_Continue;
6025+
}
6026+
6027+
/*
6028+
** Return TRUE if expression pExpr is able to return a subtype.
6029+
**
6030+
** A TRUE return does not guarantee that a subtype will be returned.
6031+
** It only indicates that a subtype return is possible. False positives
6032+
** are acceptable as they only disable an optimization. False negatives,
6033+
** on the other hand, can lead to incorrect answers.
6034+
*/
6035+
static int sqlite3ExprCanReturnSubtype(Parse *pParse, Expr *pExpr){
6036+
Walker w;
6037+
memset(&w, 0, sizeof(w));
6038+
w.pParse = pParse;
6039+
w.xExprCallback = exprNodeCanReturnSubtype;
6040+
sqlite3WalkExpr(&w, pExpr);
6041+
return w.eCode;
6042+
}
6043+
59926044
/*
59936045
** The index pIdx is used by a query and contains one or more expressions.
59946046
** In other words pIdx is an index on an expression. iIdxCur is the cursor
@@ -6022,19 +6074,11 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
60226074
continue;
60236075
}
60246076
if( sqlite3ExprIsConstant(0,pExpr) ) continue;
6025-
if( pExpr->op==TK_FUNCTION ){
6077+
if( pExpr->op==TK_FUNCTION && sqlite3ExprCanReturnSubtype(pParse,pExpr) ){
60266078
/* Functions that might set a subtype should not be replaced by the
60276079
** value taken from an expression index since the index omits the
60286080
** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
6029-
int n;
6030-
FuncDef *pDef;
6031-
sqlite3 *db = pParse->db;
6032-
assert( ExprUseXList(pExpr) );
6033-
n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
6034-
pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
6035-
if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
6036-
continue;
6037-
}
6081+
continue;
60386082
}
60396083
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
60406084
if( p==0 ) break;

test/indexexpr1.test

+52
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,58 @@ do_execsql_test indexexpr1-2200 {
615615
GROUP BY t2.type, t1.tag
616616
) v ON v.type = 0 AND v.tag = u.tag;
617617
} {7 100 8 101}
618+
do_execsql_test indexexpr1-2210 {
619+
DROP TABLE t1;
620+
CREATE TABLE t1(x INT, y TEXT);
621+
INSERT INTO t1(x,y) VALUES(1,'{b:5}');
622+
SELECT json_insert('{}', '$.a', coalesce(null,json(y)))->>'$.a.b' FROM t1;
623+
} {5}
624+
db null NULL
625+
do_execsql_test indexexpr1-2211 {
626+
CREATE INDEX t1j ON t1(coalesce(null,json(y)));
627+
SELECT json_insert('{}', '$.a', coalesce(null,json(y)))->>'$.a.b' FROM t1;
628+
} {5}
629+
do_execsql_test indexexpr1-2220 {
630+
DROP INDEX t1j;
631+
SELECT json_insert('{}', '$.a', iif(1,json(y),123))->>'$.a.b' FROM t1;
632+
} {5}
633+
do_execsql_test indexexpr1-2221 {
634+
CREATE INDEX t1j ON t1(iif(1,json(y),123));
635+
SELECT json_insert('{}', '$.a', iif(1,json(y),123))->>'$.a.b' FROM t1;
636+
} {5}
637+
do_execsql_test indexexpr1-2230 {
638+
DROP INDEX t1j;
639+
SELECT json_insert('{}', '$.a', ifnull(NULL,json(y)))->>'$.a.b' FROM t1;
640+
} {5}
641+
do_execsql_test indexexpr1-2231 {
642+
CREATE INDEX t1j ON t1(ifnull(NULL,json(y)));
643+
SELECT json_insert('{}', '$.a', ifnull(NULL,json(y)))->>'$.a.b' FROM t1;
644+
} {5}
645+
do_execsql_test indexexpr1-2240 {
646+
DROP INDEX t1j;
647+
SELECT json_insert('{}', '$.a', nullif(json(y),8))->>'$.a.b' FROM t1;
648+
} {5}
649+
do_execsql_test indexexpr1-2241 {
650+
CREATE INDEX t1j ON t1(nullif(json(y),8));
651+
SELECT json_insert('{}', '$.a', nullif(json(y),8))->>'$.a.b' FROM t1;
652+
} {5}
653+
do_execsql_test indexexpr1-2250 {
654+
DROP INDEX t1j;
655+
SELECT json_insert('{}', '$.a', min('~',json(y)))->>'$.a.b' FROM t1;
656+
} {5}
657+
do_execsql_test indexexpr1-2251 {
658+
CREATE INDEX t1j ON t1(min('~',json(y)));
659+
SELECT json_insert('{}', '$.a', min('~',json(y)))->>'$.a.b' FROM t1;
660+
} {5}
661+
do_execsql_test indexexpr1-2260 {
662+
DROP INDEX t1j;
663+
SELECT json_insert('{}', '$.a', max('...',json(y)))->>'$.a.b' FROM t1;
664+
} {5}
665+
do_execsql_test indexexpr1-2261 {
666+
CREATE INDEX t1j ON t1(max('...',json(y)));
667+
SELECT json_insert('{}', '$.a', max('...',json(y)))->>'$.a.b' FROM t1;
668+
} {5}
669+
618670

619671
# 2023-11-08 Forum post https://sqlite.org/forum/forumpost/68d284c86b082c3e
620672
#

0 commit comments

Comments
 (0)