diff --git a/MODULE.bazel b/MODULE.bazel index f601dbba686..ddd74aecb08 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -16,8 +16,6 @@ archive_override( "//:patches/sqlite/0002-macOS-missing-PATH-fix.patch", "//:patches/sqlite/0003-sqlite-complete-early-exit.patch", "//:patches/sqlite/0004-authorizer-rename-to-destination-name.patch", - "//:patches/sqlite/0005-restrict-internal-functions-to-nested-parse.patch", - "//:patches/sqlite/0006-call-authorizer-in-default-column-expressions.patch", ], remote_file_integrity = { "MODULE.bazel": "sha256-y8b6x7BNbvOuFQxzh1vbyJ/1F/RP67Ho3gJUJU3wZeE=", @@ -26,9 +24,9 @@ archive_override( remote_file_urls = { "MODULE.bazel": ["https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/refs/heads/main/modules/sqlite3/3.53.3/MODULE.bazel"], }, - sha256 = "d18fa15aec74d8c17e1463f861095adc01b5ad190256acb4f91d22f0368d232b", - strip_prefix = "sqlite-src-3530400", - url = "https://sqlite.org/2026/sqlite-src-3530400.zip", + sha256 = "387e7f6cad4797b17848c07d453dc6606917bb356a6cfe5a3abafd38c240c71b", + strip_prefix = "sqlite-src-3540100", + url = "https://sqlite.org/2026/sqlite-src-3540100.zip", ) # rules_android/rules_go are not used by ourselves, but protobuf pulls in outdated versions that are diff --git a/patches/sqlite/0001-row-counts-plain.patch b/patches/sqlite/0001-row-counts-plain.patch index 9ea5566df94..66d9a8add79 100644 --- a/patches/sqlite/0001-row-counts-plain.patch +++ b/patches/sqlite/0001-row-counts-plain.patch @@ -1,7 +1,7 @@ diff -u5 -r sqlite-src-pristine/src/shell.c.in sqlite-src-modified/src/shell.c.in --- sqlite-src-pristine/src/shell.c.in 2026-08-19 19:37:52 +++ sqlite-src-modified/src/shell.c.in 2026-08-19 21:03:33 -@@ -2942,10 +2942,15 @@ +@@ -3573,10 +3573,15 @@ cli_printf(out, "Number of times run: %d\n", iCur); iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset); @@ -15,8 +15,8 @@ diff -u5 -r sqlite-src-pristine/src/shell.c.in sqlite-src-modified/src/shell.c.i } #ifdef __linux__ - displayLinuxIoStats(pArg->out); - #endif + if( (pArg->mStats & CLISTAT_IO)!=0 ){ + displayLinuxIoStats(pArg->out); diff -u5 -r sqlite-src-pristine/src/sqlite.h.in sqlite-src-modified/src/sqlite.h.in --- sqlite-src-pristine/src/sqlite.h.in 2026-08-19 19:37:52 +++ sqlite-src-modified/src/sqlite.h.in 2026-08-19 21:02:27 diff --git a/patches/sqlite/0003-sqlite-complete-early-exit.patch b/patches/sqlite/0003-sqlite-complete-early-exit.patch index 52c638b3233..ef34a835062 100644 --- a/patches/sqlite/0003-sqlite-complete-early-exit.patch +++ b/patches/sqlite/0003-sqlite-complete-early-exit.patch @@ -1,19 +1,33 @@ ---- sqlite-src-pristine/src/complete.c 2023-11-01 22:31:37 -+++ sqlite-src-modified/src/complete.c 2024-03-14 12:51:32 -@@ -99,14 +99,21 @@ +--- sqlite-src-pristine/src/complete.c ++++ sqlite-src-modified/src/complete.c +@@ -54,10 +54,13 @@ + ** if the entire string ends with ";" and possibly with ";END;" if the + ** string is a CREATE TRIGGER statement. A non-zero return indicates + ** that the string is empty or incomplete. Bits of the return value + ** indicate what is missing and is needed to close out the statement. + ** ++** If firstOnly is true, stop after the first complete statement. ++** If pLength is not NULL, store the number of bytes consumed in it. ++** + ** Special handling is require for CREATE TRIGGER statements. + ** Whenever the CREATE TRIGGER keywords are seen, the statement + ** must end with ";END;". + ** + ** Let the return code be a value R. R is split up into various +@@ -139,16 +142,21 @@ ** ** If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed ** to recognize the end of a trigger can be omitted. All we have to do ** is look for a semicolon that is not part of an string or comment. */ --int sqlite3_complete(const char *zSql){ -+int sqlite3_complete(const char *zSql) { -+ return sqlite3_complete_length(zSql, 0) != 0; -+} -+ -+int sqlite3_complete_length(const char *zSql, int firstOnly){ +-sqlite3_int64 sqlite3_incomplete(const char *zSql){ ++static sqlite3_int64 sqlite3Incomplete( ++ const char *zSql, int firstOnly, int *pLength ++){ u8 state = 0; /* Current state, using numbers defined in header comment */ u8 token; /* Value of the next token */ + u8 pending = 0; /* unmatched structure character */ + int nParen = 0; /* Nested parentheses */ + /* Store the original pointer for later index calculations */ + const char *initialZSql = zSql; @@ -23,32 +37,49 @@ ** statement. This is the normal case. */ static const u8 trans[8][8] = { -@@ -254,12 +261,16 @@ +@@ -328,22 +336,35 @@ break; } } state = trans[state][token]; zSql++; + -+ // Once we have found a single complete statement, return its length -+ if (firstOnly && state==1) return zSql - initialZSql; ++ // Once we have found a single complete statement, stop scanning ++ if( firstOnly && state==1 ) break; } -- return state==1; -+ // Otherwise only return the length if the entire input is valid -+ return state==1 ? zSql - initialZSql : 0; + incomplete_finish: ++ if( pLength ) *pLength = zSql - initialZSql; + if( state==0 && pending==0 ) return SQLITE_EMPTY; + if( state==1 ) nParen = 0; + return (i64)((((u64)nParen)<<32) | + ((u64)pending<<16) | + ((u64)statemap[state]<<8) | + (state>1 || pending!=0)); } ++sqlite3_int64 sqlite3_incomplete(const char *zSql){ ++ return sqlite3Incomplete(zSql, 0, 0); ++} + int sqlite3_complete(const char *zSql){ + return sqlite3_incomplete(zSql)==0; + } ++int sqlite3_complete_length(const char *zSql, int firstOnly){ ++ int length = 0; ++ sqlite3_int64 incomplete = sqlite3Incomplete(zSql, firstOnly, &length); ++ // Only return the length if the requested input is complete ++ return incomplete==0 ? length : 0; ++} #ifndef SQLITE_OMIT_UTF16 /* ** This routine is the same as the sqlite3_complete() routine described -diff -u5 -r sqlite-src-pristine/src/sqlite.h.in sqlite-src-modified/src/sqlite.h.in ---- sqlite-src-pristine/src/sqlite.h.in 2023-11-01 22:31:37 -+++ sqlite-src-modified/src/sqlite.h.in 2024-03-12 12:48:37 -@@ -2775,10 +2775,14 @@ - ** UTF-16 string in native byte order. + ** above, except that the parameter is required to be UTF-16 encoded, not +--- sqlite-src-pristine/src/sqlite.h.in ++++ sqlite-src-modified/src/sqlite.h.in +@@ -3004,10 +3004,14 @@ */ int sqlite3_complete(const char *sql); int sqlite3_complete16(const void *sql); + sqlite3_int64 sqlite3_incomplete(const char *sql); +// workerd addition: measure the length of the first (or all) complete +// statements in the input. diff --git a/patches/sqlite/0005-restrict-internal-functions-to-nested-parse.patch b/patches/sqlite/0005-restrict-internal-functions-to-nested-parse.patch deleted file mode 100644 index 114fda7582d..00000000000 --- a/patches/sqlite/0005-restrict-internal-functions-to-nested-parse.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/src/expr.c b/src/expr.c ---- a/src/expr.c -+++ b/src/expr.c -@@ -5379,7 +5379,12 @@ expr_code_doover: - pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0); - } - #endif -- if( pDef==0 || pDef->xFinalize!=0 ){ -+ if( pDef==0 -+ || pDef->xFinalize!=0 -+ || ((pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && -+ !pParse->nested && -+ (db->mDbFlags & DBFLAG_InternalFunc)==0) -+ ){ - sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr); - break; - } diff --git a/patches/sqlite/0006-call-authorizer-in-default-column-expressions.patch b/patches/sqlite/0006-call-authorizer-in-default-column-expressions.patch deleted file mode 100644 index 762ec7d34d0..00000000000 --- a/patches/sqlite/0006-call-authorizer-in-default-column-expressions.patch +++ /dev/null @@ -1,332 +0,0 @@ -diff --git a/src/build.c b/src/build.c ---- a/src/build.c -+++ b/src/build.c -@@ -700,21 +700,61 @@ - sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr); - pList->a[pCol->iDflt-1].pExpr = pExpr; - } - } - -+#ifndef SQLITE_OMIT_AUTHORIZATION -+/* -+** If the expression contains any TK_FUNCTION, send it to the authorizer -+** and if the authorization fails then raise an error. -+*/ -+static int authFunctions(Walker *pWalker, Expr *p){ -+ if( p->op==TK_FUNCTION ){ -+ Parse *pParse = pWalker->pParse; -+ int rc = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, p->u.zToken, 0); -+ if( rc ){ -+ sqlite3ErrorMsg(pParse, "not authorized to use function: %#T", p); -+ return WRC_Abort; -+ } -+ } -+ return WRC_Continue; -+} -+static void sqlite3FuncAuth(Parse *pParse, Expr *pExpr){ -+ Walker w; -+ memset(&w, 0, sizeof(w)); -+ w.xExprCallback = authFunctions; -+ w.pParse = pParse; -+ sqlite3WalkExpr(&w,pExpr); -+} -+#endif /* SQLITE_OMIT_AUTHORIZATION */ -+ - /* - ** Return the expression associated with a column. The expression might be - ** the DEFAULT clause or the AS clause of a generated column. - ** Return NULL if the column has no associated expression. -+** -+** There are two variants of this routine. sqlite3ColumnExpr() just -+** returns the expression with no side effects. sqlite3ColumnExprAuth() -+** takes the extra step of invoking the authorizer (if one is defined) -+** and raising an error if the returned expression uses any unauthorized -+** SQL function. - */ - Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ - if( pCol->iDflt==0 ) return 0; - if( !IsOrdinaryTable(pTab) ) return 0; - if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; - if( NEVER(pTab->u.tab.pDfltList->nExpriDflt) ) return 0; - return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; -+} -+Expr *sqlite3ColumnExprAuth(Table *pTab, Column *pCol, Parse *pParse){ -+ Expr *pExpr = sqlite3ColumnExpr(pTab,pCol); -+#ifndef SQLITE_OMIT_AUTHORIZATION -+ if( pParse->db->xAuth!=0 ){ -+ sqlite3FuncAuth(pParse, pExpr); -+ } -+#endif -+ return pExpr; - } - - /* - ** Suppress false-positive warning message generated with -O3 in GCC - ** on the second call to sqlite3Strlen30() in the sqlite3ColumnSetColl() -@@ -1778,10 +1818,17 @@ - x.pLeft = pExpr; - x.flags = EP_Skip; - pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); - sqlite3DbFree(db, x.u.zToken); - sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr); -+#ifndef SQLITE_OMIT_AUTHORIZATION -+ /* Reject unauthorized functions from DEFAULT clauses */ -+ if( db->init.busy==0 && db->xAuth!=0 ){ -+ sqlite3FuncAuth(pParse, pExpr); -+ } -+#endif /* SQLITE_OMIT_AUTHORIZER */ -+ - } - } - if( IN_RENAME_OBJECT ){ - sqlite3RenameExprUnmap(pParse, pExpr); - } -@@ -2643,11 +2690,10 @@ - } - } - #else - #define markExprListImmutable(X) /* no-op */ - #endif /* SQLITE_DEBUG */ -- - - /* - ** This routine is called to report the final ")" that terminates - ** a CREATE TABLE statement. - ** - -diff --git a/src/expr.c b/src/expr.c ---- a/src/expr.c -+++ b/src/expr.c -@@ -4531,16 +4531,16 @@ - assert( pTab!=0 ); - assert( iCol!=XN_EXPR ); - if( iCol<0 || iCol==pTab->iPKey ){ - sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); - VdbeComment((v, "%s.rowid", pTab->zName)); -- }else{ -- int op; -+ }else{ - int x; - if( IsVirtual(pTab) ){ -- op = OP_VColumn; - x = iCol; -+ sqlite3VdbeAddOp3(v, OP_VColumn, iTabCur, x, regOut); -+ return; - #ifndef SQLITE_OMIT_GENERATED_COLUMNS - }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ - Parse *pParse = sqlite3VdbeParser(v); - if( pCol->colFlags & COLFLAG_BUSY ){ - sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", -@@ -4556,17 +4556,15 @@ - return; - #endif - }else if( !HasRowid(pTab) ){ - testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); - x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); -- op = OP_Column; - }else{ - x = sqlite3TableColumnToStorage(pTab,iCol); - testcase( x!=iCol ); -- op = OP_Column; - } -- sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); -+ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, x, regOut); - sqlite3ColumnDefault(v, pTab, iCol, regOut); - } - } - - /* - -diff --git a/src/fkey.c b/src/fkey.c ---- a/src/fkey.c -+++ b/src/fkey.c -@@ -1304,11 +1304,11 @@ - if( pCol->colFlags & COLFLAG_GENERATED ){ - testcase( pCol->colFlags & COLFLAG_VIRTUAL ); - testcase( pCol->colFlags & COLFLAG_STORED ); - pDflt = 0; - }else{ -- pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol); -+ pDflt = sqlite3ColumnExprAuth(pFKey->pFrom, pCol, pParse); - } - if( pDflt ){ - pNew = sqlite3ExprDup(db, pDflt, 0); - }else{ - pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); - -diff --git a/src/insert.c b/src/insert.c ---- a/src/insert.c -+++ b/src/insert.c -@@ -1385,11 +1385,11 @@ - continue; - }else if( pColumn==0 ){ - /* Hidden columns that are not explicitly named in the INSERT - ** get their default value */ - sqlite3ExprCodeFactorable(pParse, -- sqlite3ColumnExpr(pTab, &pTab->aCol[i]), -+ sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), - iRegStore); - continue; - } - } - if( pColumn ){ -@@ -1397,19 +1397,19 @@ - assert( j>=0 && j<=pColumn->nId ); - if( j==0 ){ - /* A column not named in the insert column list gets its - ** default value */ - sqlite3ExprCodeFactorable(pParse, -- sqlite3ColumnExpr(pTab, &pTab->aCol[i]), -+ sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), - iRegStore); - continue; - } - k = j - 1; - }else if( nColumn==0 ){ - /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ - sqlite3ExprCodeFactorable(pParse, -- sqlite3ColumnExpr(pTab, &pTab->aCol[i]), -+ sqlite3ColumnExprAuth(pTab, &pTab->aCol[i], pParse), - iRegStore); - continue; - }else{ - k = i - nHidden; - } -@@ -2003,11 +2003,11 @@ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg); - VdbeCoverage(v); - assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); - nSeenReplace++; - sqlite3ExprCodeCopy(pParse, -- sqlite3ColumnExpr(pTab, pCol), iReg); -+ sqlite3ColumnExprAuth(pTab, pCol, pParse), iReg); - sqlite3VdbeJumpHere(v, addr1); - break; - } - case OE_Abort: - sqlite3MayAbort(pParse); - -diff --git a/src/pragma.c b/src/pragma.c ---- a/src/pragma.c -+++ b/src/pragma.c -@@ -1931,12 +1931,12 @@ - p1 = -1; - p3 = 3; - }else{ - if( pCol->iDflt ){ - sqlite3_value *pDfltValue = 0; -- sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db), -- pCol->affinity, &pDfltValue); -+ sqlite3ValueFromExpr(db, sqlite3ColumnExprAuth(pTab,pCol,pParse), -+ ENC(db), pCol->affinity, &pDfltValue); - if( pDfltValue ){ - p4 = sqlite3_value_type(pDfltValue); - sqlite3ValueFree(pDfltValue); - } - } - -diff --git a/src/printf.c b/src/printf.c ---- a/src/printf.c -+++ b/src/printf.c -@@ -1179,14 +1179,17 @@ - /* - ** If pExpr has a byte offset for the start of a token, record that as - ** as the error offset. - */ - void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ -- while( pExpr -- && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0) -- ){ -- pExpr = pExpr->pLeft; -+ while( pExpr ){ -+ if( ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) ) return; -+ if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0 ){ -+ pExpr = pExpr->pLeft; -+ }else{ -+ break; -+ } - } - if( pExpr==0 ) return; - if( ExprHasProperty(pExpr, EP_FromDDL) ) return; - db->errByteOffset = pExpr->w.iOfst; - } - -diff --git a/src/sqliteInt.h b/src/sqliteInt.h ---- a/src/sqliteInt.h -+++ b/src/sqliteInt.h -@@ -5074,10 +5074,11 @@ - void sqlite3ResetOneSchema(sqlite3*,int); - void sqlite3CollapseDatabaseArray(sqlite3*); - void sqlite3CommitInternalChanges(sqlite3*); - void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*); - Expr *sqlite3ColumnExpr(Table*,Column*); -+Expr *sqlite3ColumnExprAuth(Table*,Column*,Parse*); - void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl); - const char *sqlite3ColumnColl(Column*); - void sqlite3DeleteColumnNames(sqlite3*,Table*); - void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); - int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); - -diff --git a/src/update.c b/src/update.c ---- a/src/update.c -+++ b/src/update.c -@@ -56,30 +56,47 @@ - ** If column as REAL affinity and the table is an ordinary b-tree table - ** (not a virtual table) then the value might have been stored as an - ** integer. In that case, add an OP_RealAffinity opcode to make sure - ** it has been converted into REAL. - */ --void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ -+static SQLITE_NOINLINE void columnDefaultUncommonCase( -+ Vdbe *v, /* Byte code under construction */ -+ Table *pTab, /* The table */ -+ Column *pCol, /* Which column of the table */ -+ int iReg /* Register in which results are stored */ -+){ -+ sqlite3_value *pValue = 0; -+ u8 enc = ENC(sqlite3VdbeDb(v)); -+ Parse *pParse = sqlite3VdbeParser(v); -+ assert( !IsView(pTab) ); -+ sqlite3ValueFromExpr(sqlite3VdbeDb(v), -+ sqlite3ColumnExprAuth(pTab,pCol,pParse), enc, -+ pCol->affinity, &pValue); -+ if( pValue ){ -+ sqlite3VdbeAppendP4(v, pValue, P4_MEM); -+ } -+#ifndef SQLITE_OMIT_FLOATING_POINT -+ if( pCol->affinity==SQLITE_AFF_REAL ){ -+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); -+ } -+#endif -+} -+void sqlite3ColumnDefault( -+ Vdbe *v, /* Byte code under construction */ -+ Table *pTab, /* The table */ -+ int i, /* Which column of the table */ -+ int iReg /* Register in which results are stored */ -+){ - Column *pCol; - assert( pTab!=0 ); - assert( pTab->nCol>i ); - pCol = &pTab->aCol[i]; - if( pCol->iDflt ){ -- sqlite3_value *pValue = 0; -- u8 enc = ENC(sqlite3VdbeDb(v)); -- assert( !IsView(pTab) ); -- VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName)); -- assert( inCol ); -- sqlite3ValueFromExpr(sqlite3VdbeDb(v), -- sqlite3ColumnExpr(pTab,pCol), enc, -- pCol->affinity, &pValue); -- if( pValue ){ -- sqlite3VdbeAppendP4(v, pValue, P4_MEM); -- } -+ columnDefaultUncommonCase(v,pTab,pCol,iReg); - } - #ifndef SQLITE_OMIT_FLOATING_POINT -- if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){ -+ if( pCol->affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); - } - #endif - }