aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2009-11-11 00:24:31 +0000
committerdrh <drh@noemail.net>2009-11-11 00:24:31 +0000
commitae6bb9570b6d6ef7893a9571d0fa10b43d936f61 (patch)
tree5c9ee74af1b3a4dc9d4912d51af98525357395ae /src
parent63b38789210cab605cbff76932f4be20323a5724 (diff)
downloadsqlite-ae6bb9570b6d6ef7893a9571d0fa10b43d936f61.tar.gz
sqlite-ae6bb9570b6d6ef7893a9571d0fa10b43d936f61.zip
Generate VDBE code for the built-in COALESCE() and IFNULL() functions. This
allows unused arguments to never be evaluated, which is a performance win when the unused argument is a subquery. FossilOrigin-Name: 30055b257c3c65f8123cad5ac6c62c4c6ca2c900
Diffstat (limited to 'src')
-rw-r--r--src/expr.c21
-rw-r--r--src/func.c16
-rw-r--r--src/sqliteInt.h1
3 files changed, 36 insertions, 2 deletions
diff --git a/src/expr.c b/src/expr.c
index 0cc309361..249ab9037 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2394,6 +2394,27 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break;
}
+
+ /* Attempt a direct implementation of the built-in COALESCE() and
+ ** IFNULL() functions. This avoids unnecessary evalation of
+ ** arguments past the first non-NULL argument.
+ */
+ if( pDef->flags & SQLITE_FUNC_COALESCE ){
+ int endCoalesce = sqlite3VdbeMakeLabel(v);
+ assert( nFarg>=2 );
+ sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
+ for(i=1; i<nFarg; i++){
+ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
+ sqlite3ExprCacheRemove(pParse, target);
+ sqlite3ExprCachePush(pParse);
+ sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
+ sqlite3ExprCachePop(pParse, 1);
+ }
+ sqlite3VdbeResolveLabel(v, endCoalesce);
+ break;
+ }
+
+
if( pFarg ){
r1 = sqlite3GetTempRange(pParse, nFarg);
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
diff --git a/src/func.c b/src/func.c
index 2766fa3b1..980d04edb 100644
--- a/src/func.c
+++ b/src/func.c
@@ -335,6 +335,14 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
+
+#if 0 /* This function is never used. */
+/*
+** The COALESCE() and IFNULL() functions used to be implemented as shown
+** here. But now they are implemented as VDBE code so that unused arguments
+** do not have to be computed. This legacy implementation is retained as
+** comment.
+*/
/*
** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
** All three do the same thing. They return the first non-NULL
@@ -353,6 +361,8 @@ static void ifnullFunc(
}
}
}
+#endif /* NOT USED */
+#define ifnullFunc versionFunc /* Substitute function - never called */
/*
** Implementation of random(). Return a random integer.
@@ -1437,10 +1447,12 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, -1, 0, 0, ifnullFunc ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
+/* FUNCTION(coalesce, -1, 0, 0, ifnullFunc ), */
+ {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0},
FUNCTION(hex, 1, 0, 0, hexFunc ),
- FUNCTION(ifnull, 2, 0, 1, ifnullFunc ),
+/* FUNCTION(ifnull, 2, 0, 0, ifnullFunc ), */
+ {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0},
FUNCTION(random, 0, 0, 0, randomFunc ),
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 24debbabe..16c1d6b38 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -959,6 +959,7 @@ struct FuncDef {
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */
#define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are