diff options
author | drh <> | 2025-07-18 12:10:15 +0000 |
---|---|---|
committer | drh <> | 2025-07-18 12:10:15 +0000 |
commit | 74cc109780ee33138db6e7ed076426604131b8c6 (patch) | |
tree | 3ecd297d28c2aa81e60d437c03219386e9b51ad2 /src | |
parent | 01a2953350395ca3b0962c9a0245db847f271b82 (diff) | |
download | sqlite-74cc109780ee33138db6e7ed076426604131b8c6.tar.gz sqlite-74cc109780ee33138db6e7ed076426604131b8c6.zip |
Ensure that the accumulator for an aggregate always gets initialized,
even when the aggregate is on the right side of a LEFT JOIN and never
gets evaluated. This fixes a problem introduced by [663f5dd32d9db832]
and found by dbsqlfuzz. Test cases in TH3.
FossilOrigin-Name: 235cf6586b9ac914a32bd8adfd460daae998687f02f0998a7aa3c6bfc857d1c9
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 25 | ||||
-rw-r--r-- | src/select.c | 1 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 |
3 files changed, 28 insertions, 0 deletions
diff --git a/src/expr.c b/src/expr.c index 3f040309a..dba0aa2de 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4989,6 +4989,12 @@ expr_code_doover: sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } + case TK_NULLS: { + /* Set a range of registers to NULL. pExpr->y.nReg registers starting + ** with target */ + sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1); + return target; + } default: { /* Make NULL the default case so that if a bug causes an illegal ** Expr node to be passed into this function, it will be handled @@ -5699,6 +5705,25 @@ int sqlite3ExprCodeRunJustOnce( } /* +** Make arrangements to invoke OP_Null on a range of registers +** during initialization. +*/ +SQLITE_NOINLINE void sqlite3ExprNullRegisterRange( + Parse *pParse, /* Parsing context */ + int iReg, /* First register to set to NULL */ + int nReg /* Number of sequential registers to NULL out */ +){ + u8 okConstFactor = pParse->okConstFactor; + Expr t; + memset(&t, 0, sizeof(t)); + t.op = TK_NULLS; + t.y.nReg = nReg; + pParse->okConstFactor = 1; + sqlite3ExprCodeRunJustOnce(pParse, &t, iReg); + pParse->okConstFactor = okConstFactor; +} + +/* ** Generate code to evaluate an expression and store the results ** into a register. Return the register number where the results ** are stored. diff --git a/src/select.c b/src/select.c index 1b1266313..665c30933 100644 --- a/src/select.c +++ b/src/select.c @@ -8482,6 +8482,7 @@ int sqlite3Select( sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag); VdbeComment((v, "clear abort flag")); sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1); + sqlite3ExprNullRegisterRange(pParse, iAMem, pGroupBy->nExpr); /* Begin a loop that will extract all source rows in GROUP BY order. ** This might involve two separate loops with an OP_Sort in between, or diff --git a/src/sqliteInt.h b/src/sqliteInt.h index df0e1c3ba..a09c94ae6 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3082,6 +3082,7 @@ struct Expr { Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL ** for a column of an index on an expression */ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */ + int nReg; /* TK_NULLS: Number of registers to NULL out */ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */ int iAddr; /* Subroutine entry address */ int regReturn; /* Register used to hold return address */ @@ -5119,6 +5120,7 @@ void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); +void sqlite3ExprNullRegisterRange(Parse*, int, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); |