mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
Merge the latest enhancements from trunk.
FossilOrigin-Name: bd57e6d923d3b04f0a07aaf18bf389d2b2b7efc7c57e8cb37e6ef910662d8397
This commit is contained in:
168
src/expr.c
168
src/expr.c
@@ -3574,6 +3574,106 @@ 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;
|
||||
}
|
||||
|
||||
default: {
|
||||
/* The UNLIKELY() function is a no-op. The result is the value
|
||||
** of the first argument.
|
||||
*/
|
||||
assert( nFarg==1 || nFarg==2 );
|
||||
target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
|
||||
break;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
** Test-only SQL functions that are only usable if enabled
|
||||
** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
|
||||
*/
|
||||
case INLINEFUNC_expr_compare: {
|
||||
/* Compare two expressions using sqlite3ExprCompare() */
|
||||
assert( nFarg==2 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
|
||||
target);
|
||||
break;
|
||||
}
|
||||
|
||||
case INLINEFUNC_expr_implies_expr: {
|
||||
/* Compare two expressions using sqlite3ExprImpliesExpr() */
|
||||
assert( nFarg==2 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
|
||||
target);
|
||||
break;
|
||||
}
|
||||
|
||||
case INLINEFUNC_implies_nonnull_row: {
|
||||
/* REsult of sqlite3ExprImpliesNonNullRow() */
|
||||
Expr *pA1;
|
||||
assert( nFarg==2 );
|
||||
pA1 = pFarg->a[1].pExpr;
|
||||
if( pA1->op==TK_COLUMN ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
|
||||
target);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 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
|
||||
@@ -3954,48 +4054,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 );
|
||||
@@ -4078,7 +4141,7 @@ expr_code_doover:
|
||||
if( constMask==0 ){
|
||||
sqlite3ReleaseTempRange(pParse, r1, nFarg);
|
||||
}else{
|
||||
sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask);
|
||||
sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
@@ -4430,7 +4493,13 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
|
||||
if( inReg!=target && pParse->pVdbe ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
|
||||
u8 op;
|
||||
if( ExprHasProperty(pExpr,EP_Subquery) ){
|
||||
op = OP_Copy;
|
||||
}else{
|
||||
op = OP_SCopy;
|
||||
}
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5297,11 +5366,12 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Prune;
|
||||
|
||||
case TK_AND:
|
||||
assert( pWalker->eCode==0 );
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
if( pWalker->eCode ){
|
||||
pWalker->eCode = 0;
|
||||
sqlite3WalkExpr(pWalker, pExpr->pRight);
|
||||
if( pWalker->eCode==0 ){
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
if( pWalker->eCode ){
|
||||
pWalker->eCode = 0;
|
||||
sqlite3WalkExpr(pWalker, pExpr->pRight);
|
||||
}
|
||||
}
|
||||
return WRC_Prune;
|
||||
|
||||
@@ -5730,7 +5800,7 @@ int sqlite3GetTempReg(Parse *pParse){
|
||||
*/
|
||||
void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
|
||||
if( iReg ){
|
||||
sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0);
|
||||
sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
|
||||
if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
||||
}
|
||||
@@ -5759,7 +5829,7 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
|
||||
sqlite3ReleaseTempReg(pParse, iReg);
|
||||
return;
|
||||
}
|
||||
sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0);
|
||||
sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0);
|
||||
if( nReg>pParse->nRangeReg ){
|
||||
pParse->nRangeReg = nReg;
|
||||
pParse->iRangeReg = iReg;
|
||||
|
||||
Reference in New Issue
Block a user