1
0
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:
drh
2020-01-01 13:55:08 +00:00
parent 6d67aff0e3
commit 25c4296bd9
5 changed files with 107 additions and 56 deletions

View File

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

View File

@@ -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();

View File

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