mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-19 21:43:15 +03:00
Factor out code generation for in-line SQL functions into a separate routine
inside of expr.c. FossilOrigin-Name: 586a65a28fc6cac77309612abc32a2e1017c65e0387f9f438f5d8ac8406da8eb
This commit is contained in:
106
src/expr.c
106
src/expr.c
@@ -3573,6 +3573,69 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
|
||||
return iResult;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to implement special SQL functions that are implemented
|
||||
** in-line rather than by using the usual callbacks.
|
||||
*/
|
||||
static int exprCodeInlineFunction(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprList *pFarg, /* List of function arguments */
|
||||
int iFuncId, /* Function ID. One of the INTFUNC_... values */
|
||||
int target /* Store function result in this register */
|
||||
){
|
||||
int nFarg;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
assert( pFarg!=0 );
|
||||
nFarg = pFarg->nExpr;
|
||||
assert( nFarg>0 ); /* All in-line functions have at least one argument */
|
||||
switch( iFuncId ){
|
||||
case INLINEFUNC_coalesce: {
|
||||
/* Attempt a direct implementation of the built-in COALESCE() and
|
||||
** IFNULL() functions. This avoids unnecessary evaluation of
|
||||
** arguments past the first non-NULL argument.
|
||||
*/
|
||||
int endCoalesce = sqlite3VdbeMakeLabel(pParse);
|
||||
int i;
|
||||
assert( nFarg>=2 );
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
for(i=1; i<nFarg; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endCoalesce);
|
||||
break;
|
||||
}
|
||||
|
||||
case INLINEFUNC_unlikely: {
|
||||
/* The UNLIKELY() function is a no-op. The result is the value
|
||||
** of the first argument.
|
||||
*/
|
||||
assert( nFarg>=1 );
|
||||
target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
case INLINEFUNC_affinity: {
|
||||
/* The AFFINITY() function evaluates to a string that describes
|
||||
** the type affinity of the argument. This is used for testing of
|
||||
** the SQLite type logic.
|
||||
*/
|
||||
const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
|
||||
char aff;
|
||||
assert( nFarg==1 );
|
||||
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
|
||||
sqlite3VdbeLoadString(v, target,
|
||||
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code into the current Vdbe to evaluate the given
|
||||
@@ -3953,48 +4016,11 @@ expr_code_doover:
|
||||
sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Attempt a direct implementation of the built-in COALESCE() and
|
||||
** IFNULL() functions. This avoids unnecessary evaluation of
|
||||
** arguments past the first non-NULL argument.
|
||||
*/
|
||||
if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
|
||||
int endCoalesce = sqlite3VdbeMakeLabel(pParse);
|
||||
assert( nFarg>=2 );
|
||||
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
|
||||
for(i=1; i<nFarg; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
|
||||
VdbeCoverage(v);
|
||||
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endCoalesce);
|
||||
break;
|
||||
if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
|
||||
return exprCodeInlineFunction(pParse, pFarg,
|
||||
SQLITE_PTR_TO_INT(pDef->pUserData), target);
|
||||
}
|
||||
|
||||
/* The UNLIKELY() function is a no-op. The result is the value
|
||||
** of the first argument.
|
||||
*/
|
||||
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
|
||||
assert( nFarg>=1 );
|
||||
return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The AFFINITY() function evaluates to a string that describes
|
||||
** the type affinity of the argument. This is used for testing of
|
||||
** the SQLite type logic.
|
||||
*/
|
||||
if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){
|
||||
const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
|
||||
char aff;
|
||||
assert( nFarg==1 );
|
||||
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
|
||||
sqlite3VdbeLoadString(v, target,
|
||||
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
|
||||
return target;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(i=0; i<nFarg; i++){
|
||||
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
|
||||
testcase( i==31 );
|
||||
|
||||
12
src/func.c
12
src/func.c
@@ -1921,11 +1921,11 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
||||
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
#ifdef SQLITE_DEBUG
|
||||
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
|
||||
TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
|
||||
@@ -1959,7 +1959,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION(upper, 1, 0, 0, upperFunc ),
|
||||
FUNCTION(lower, 1, 0, 0, lowerFunc ),
|
||||
FUNCTION(hex, 1, 0, 0, hexFunc ),
|
||||
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
VFUNCTION(random, 0, 0, 0, randomFunc ),
|
||||
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
@@ -1999,7 +1999,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
#endif
|
||||
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
||||
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
||||
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
};
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
|
||||
@@ -1712,12 +1712,18 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
|
||||
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
|
||||
** single query - might change over time */
|
||||
#define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
|
||||
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
|
||||
#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
|
||||
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
|
||||
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
|
||||
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
|
||||
#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
|
||||
#define SQLITE_FUNC_INLINE 0x00200000 /* Functions implemented in-line */
|
||||
|
||||
/* Identifier numbers for each in-line function */
|
||||
#define INLINEFUNC_unlikely 0 /* unlikely(EXPR) and friends */
|
||||
#define INLINEFUNC_coalesce 1 /* coalesce(EXPR,...) */
|
||||
#define INLINEFUNC_affinity 2 /* affinity(EXPR) */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
@@ -1737,6 +1743,18 @@ struct FuncDestructor {
|
||||
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
|
||||
** adds the SQLITE_DIRECTONLY flag.
|
||||
**
|
||||
** INLINE_FUNC(zName, nArg, iFuncId, mFlags)
|
||||
** zName is the name of a function that is implemented by in-line
|
||||
** byte code rather than by the usual callbacks. The iFuncId
|
||||
** parameter determines the function id. The mFlags parameter is
|
||||
** optional SQLITE_FUNC_ flags for this function.
|
||||
**
|
||||
** TEST_FUNC(zName, nArg, iFuncId, mFlags)
|
||||
** zName is the name of a test-only function implemented by in-line
|
||||
** byte code rather than by the usual callbacks. The iFuncId
|
||||
** parameter determines the function id. The mFlags parameter is
|
||||
** optional SQLITE_FUNC_ flags for this function.
|
||||
**
|
||||
** DFUNCTION(zName, nArg, iArg, bNC, xFunc)
|
||||
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
|
||||
** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions
|
||||
@@ -1779,6 +1797,13 @@ struct FuncDestructor {
|
||||
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_DIRECTONLY, \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
||||
#define TEST_FUNC(zName, nArg, iArg, mFlags) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
|
||||
SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
||||
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
|
||||
0, 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
|
||||
Reference in New Issue
Block a user