diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/sqlite.h.in | 5 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 | ||||
-rw-r--r-- | src/window.c | 47 |
4 files changed, 52 insertions, 4 deletions
diff --git a/src/main.c b/src/main.c index a8c1d4dc6..3ef3a3d9f 100644 --- a/src/main.c +++ b/src/main.c @@ -1719,7 +1719,7 @@ int sqlite3CreateFunc( assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY ); - extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY); + extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|SQLITE_SUBTYPE); enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); #ifndef SQLITE_OMIT_UTF16 diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 521ddffdb..8136889ee 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4987,9 +4987,14 @@ int sqlite3_create_window_function( ** ** The SQLITE_DIRECTONLY flag means that the function may only be invoked ** from top-level SQL, and cannot be used in VIEWs or TRIGGERs. +** +** The SQLITE_SUBTYPE flag indicates to SQLite that the function may call +** [sqlite3_result_subtype()] in order to configure its return value with +** a sub-type. */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 +#define SQLITE_SUBTYPE 0x000100000 /* ** CAPI3REF: Deprecated Functions diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d3f7ffe26..e7c1d9c1f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1686,6 +1686,7 @@ struct FuncDestructor { #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 */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -3611,6 +3612,7 @@ struct Window { int regOne; /* Register containing constant value 1 */ int regStartRowid; int regEndRowid; + u8 bExprArgs; }; #ifndef SQLITE_OMIT_WINDOWFUNC diff --git a/src/window.c b/src/window.c index ed2e32079..b88993044 100644 --- a/src/window.c +++ b/src/window.c @@ -869,6 +869,32 @@ static void selectWindowRewriteEList( } /* +** Return true if the top-level of list pList contains an SQL function +** with the SQLITE_FUNC_SUBTYPE flag set. Return false otherwise. +*/ +int exprListContainsSubtype(Parse *pParse, ExprList *pList){ + if( pList ){ + sqlite3 *db = pParse->db; + int i; + for(i=0; i<pList->nExpr; i++){ + Expr *p = pList->a[i].pExpr; + if( p->op==TK_FUNCTION ){ + FuncDef *pDef; + int nArg = 0; + if( !ExprHasProperty(p, EP_TokenOnly) && p->x.pList ){ + nArg = p->x.pList->nExpr; + } + pDef = sqlite3FindFunction(db, p->u.zToken, nArg, db->enc, 0); + if( pDef && (pDef->funcFlags & SQLITE_FUNC_SUBTYPE) ){ + return 1; + } + } + } + } + return 0; +} + +/* ** Append a copy of each expression in expression-list pAppend to ** expression list pList. Return a pointer to the result list. */ @@ -965,8 +991,15 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** window function - one for the accumulator, another for interim ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); - pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList, 0); + ExprList *pArgs = pWin->pOwner->x.pList; + if( exprListContainsSubtype(pParse, pArgs) ){ + selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist); + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pWin->bExprArgs = 1; + }else{ + pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); + pSublist = exprListAppendList(pParse, pSublist, pArgs, 0); + } if( pWin->pFilter ){ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); @@ -1432,7 +1465,7 @@ static void windowAggStep( for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; int regArg; - int nArg = windowArgCount(pWin); + int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin); int i; assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED ); @@ -1482,6 +1515,11 @@ static void windowAggStep( VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regTmp); } + if( pWin->bExprArgs ){ + nArg = pWin->pOwner->x.pList->nExpr; + regArg = sqlite3GetTempRange(pParse, nArg); + sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0); + } if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); @@ -1492,6 +1530,9 @@ static void windowAggStep( bInverse, regArg, pWin->regAccum); sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); + if( pWin->bExprArgs ){ + sqlite3ReleaseTempRange(pParse, regArg, nArg); + } if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } |