| | @@ -16,11 +16,11 @@ |
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | | -** 92709f54d4c58cf174f305b58971a01878af with changes in files: |
| 21 | +** 4bfc6e53a95d710b7f40fa9c80d8cdd1df50 with changes in files: |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| | @@ -467,14 +467,14 @@ |
| 467 | 467 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 468 | 468 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 469 | 469 | */ |
| 470 | 470 | #define SQLITE_VERSION "3.54.0" |
| 471 | 471 | #define SQLITE_VERSION_NUMBER 3054000 |
| 472 | | -#define SQLITE_SOURCE_ID "2026-10-01 11:21:02 92709f54d4c58cf174f305b58971a01878af313157a11549b588a25216701f5c" |
| 472 | +#define SQLITE_SOURCE_ID "2026-10-05 14:22:13 4bfc6e53a95d710b7f40fa9c80d8cdd1df50d69ed8614e9800f7e6a1ca5a3c29" |
| 473 | 473 | #define SQLITE_SCM_BRANCH "trunk" |
| 474 | 474 | #define SQLITE_SCM_TAGS "" |
| 475 | | -#define SQLITE_SCM_DATETIME "2026-10-01T11:21:02.802Z" |
| 475 | +#define SQLITE_SCM_DATETIME "2026-10-05T14:22:13.597Z" |
| 476 | 476 | |
| 477 | 477 | /* |
| 478 | 478 | ** CAPI3REF: Run-Time Library Version Numbers |
| 479 | 479 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 480 | 480 | ** |
| | @@ -782,11 +782,11 @@ |
| 782 | 782 | #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ |
| 783 | 783 | #define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ |
| 784 | 784 | #define SQLITE_FULL 13 /* Insertion failed because database is full */ |
| 785 | 785 | #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ |
| 786 | 786 | #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ |
| 787 | | -#define SQLITE_EMPTY 16 /* Internal use only */ |
| 787 | +#define SQLITE_EMPTY 16 /* No content */ |
| 788 | 788 | #define SQLITE_SCHEMA 17 /* The database schema changed */ |
| 789 | 789 | #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ |
| 790 | 790 | #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ |
| 791 | 791 | #define SQLITE_MISMATCH 20 /* Data type mismatch */ |
| 792 | 792 | #define SQLITE_MISUSE 21 /* Library used incorrectly */ |
| | @@ -3294,14 +3294,18 @@ |
| 3294 | 3294 | ** ^The sqlite3_complete(X) and sqlite3_complete16(X) routines return 0 |
| 3295 | 3295 | ** if the statement is incomplete. ^If a memory allocation fails, then |
| 3296 | 3296 | ** SQLITE_NOMEM is returned. |
| 3297 | 3297 | ** |
| 3298 | 3298 | ** The [sqlite3_incomplete(X)] routine is similar to [sqlite3_complete(X)] |
| 3299 | | -** except that sqlite3_incomplete(X) returns 0 if the input X is complete |
| 3300 | | -** and non-zero if X is incomplete. The non-zero return from |
| 3299 | +** except that sqlite3_incomplete(X) returns SQLITE_OK if the input X is |
| 3300 | +** complete, SQLITE_EMPTY if input X consists entirely of whitespace and/or |
| 3301 | +** comments, SQLITE_MISUSE if X is a NULL pointer, and some other non-zero |
| 3302 | +** value if X is incomplete. The non-zero return from |
| 3301 | 3303 | ** sqlite3_incomplete(X) contains additional information about what is |
| 3302 | | -** needed to complete the input X. The sqlite3_incomplete(X) interface |
| 3304 | +** needed to complete the input X. See the header comment on the |
| 3305 | +** implemenation of the sqlite3_incomplete() routine for a full description |
| 3306 | +** of its non-zero return values. The sqlite3_incomplete(X) interface |
| 3303 | 3307 | ** is only available for UTF-8 text. |
| 3304 | 3308 | ** |
| 3305 | 3309 | ** ^None of these routines do a full parse the SQL statements and thus |
| 3306 | 3310 | ** will not detect syntactically incorrect SQL. They only determine if |
| 3307 | 3311 | ** input text has properly terminated comments, string literals, and |
| | @@ -22669,12 +22673,12 @@ |
| 22669 | 22673 | SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); |
| 22670 | 22674 | SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8); |
| 22671 | 22675 | SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); |
| 22672 | 22676 | SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); |
| 22673 | 22677 | SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); |
| 22674 | | -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int); |
| 22675 | | -SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*); |
| 22678 | +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); |
| 22679 | +SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); |
| 22676 | 22680 | SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*); |
| 22677 | 22681 | SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*); |
| 22678 | 22682 | SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *); |
| 22679 | 22683 | SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*); |
| 22680 | 22684 | SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); |
| | @@ -22912,14 +22916,16 @@ |
| 22912 | 22916 | SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db); |
| 22913 | 22917 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 22914 | 22918 | SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName); |
| 22915 | 22919 | SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); |
| 22916 | 22920 | SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); |
| 22921 | +SQLITE_PRIVATE void sqlite3VtabEponymousTableClearAll(sqlite3*); |
| 22917 | 22922 | #else |
| 22918 | 22923 | # define sqlite3ShadowTableName(A,B) 0 |
| 22919 | 22924 | # define sqlite3IsShadowTableOf(A,B,C) 0 |
| 22920 | 22925 | # define sqlite3MarkAllShadowTablesOf(A,B) |
| 22926 | +# define sqlite3VtabEponymousTableClearAll(X) |
| 22921 | 22927 | #endif |
| 22922 | 22928 | SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*); |
| 22923 | 22929 | SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*); |
| 22924 | 22930 | SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); |
| 22925 | 22931 | SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); |
| | @@ -88204,10 +88210,11 @@ |
| 88204 | 88210 | || opcode==OP_VCreate |
| 88205 | 88211 | || opcode==OP_ParseSchema |
| 88206 | 88212 | || opcode==OP_Function || opcode==OP_PureFunc |
| 88207 | 88213 | || ((opcode==OP_Halt || opcode==OP_HaltIfNull) |
| 88208 | 88214 | && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) |
| 88215 | + || (opcode==OP_MustBeInt && pOp->p2==0) |
| 88209 | 88216 | ){ |
| 88210 | 88217 | hasAbort = 1; |
| 88211 | 88218 | break; |
| 88212 | 88219 | } |
| 88213 | 88220 | if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; |
| | @@ -95696,10 +95703,15 @@ |
| 95696 | 95703 | pMem = &pUnpack->aMem[iStore]; |
| 95697 | 95704 | if( iIdx==p->pTab->iPKey ){ |
| 95698 | 95705 | sqlite3VdbeMemSetInt64(pMem, p->iKey2); |
| 95699 | 95706 | }else if( iStore>=pUnpack->nField ){ |
| 95700 | 95707 | pMem = (sqlite3_value *)columnNullValue(); |
| 95708 | + }else if( (p->pTab->aCol) |
| 95709 | + && (p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL) |
| 95710 | + && (pMem->flags & (MEM_Int|MEM_IntReal)) |
| 95711 | + ){ |
| 95712 | + sqlite3VdbeMemRealify(pMem); |
| 95701 | 95713 | } |
| 95702 | 95714 | }else{ |
| 95703 | 95715 | /* For an UPDATE, memory cell (p->iNewReg+1+iStore) contains the required |
| 95704 | 95716 | ** value. Make a copy of the cell contents and return a pointer to it. |
| 95705 | 95717 | ** It is not safe to return a pointer to the memory cell itself as the |
| | @@ -112968,27 +112980,33 @@ |
| 112968 | 112980 | ** |
| 112969 | 112981 | ** If a memory allocation error occurs, that fact is recorded in pParse->db |
| 112970 | 112982 | ** and the pExpr parameter is returned unchanged. |
| 112971 | 112983 | */ |
| 112972 | 112984 | SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken( |
| 112973 | | - const Parse *pParse, /* Parsing context */ |
| 112985 | + Parse *pParse, /* Parsing context */ |
| 112974 | 112986 | Expr *pExpr, /* Add the "COLLATE" clause to this expression */ |
| 112975 | 112987 | const Token *pCollName, /* Name of collating sequence */ |
| 112976 | 112988 | int dequote /* True to dequote pCollName */ |
| 112977 | 112989 | ){ |
| 112978 | | - if( pCollName->n>0 ){ |
| 112990 | + if( pCollName->n>0 && pParse->nErr==0 ){ |
| 112979 | 112991 | Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); |
| 112992 | + assert( pExpr!=0 ); |
| 112980 | 112993 | if( pNew ){ |
| 112981 | 112994 | pNew->pLeft = pExpr; |
| 112982 | 112995 | pNew->flags |= EP_Collate|EP_Skip; |
| 112996 | +#if SQLITE_MAX_EXPR_DEPTH>0 |
| 112997 | + pNew->nHeight = pExpr->nHeight+1; |
| 112998 | + sqlite3ExprCheckHeight(pParse, pNew->nHeight); |
| 112999 | + testcase( pParse->nErr>0 ); |
| 113000 | +#endif |
| 112983 | 113001 | pExpr = pNew; |
| 112984 | 113002 | } |
| 112985 | 113003 | } |
| 112986 | 113004 | return pExpr; |
| 112987 | 113005 | } |
| 112988 | 113006 | SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString( |
| 112989 | | - const Parse *pParse, /* Parsing context */ |
| 113007 | + Parse *pParse, /* Parsing context */ |
| 112990 | 113008 | Expr *pExpr, /* Add the "COLLATE" clause to this expression */ |
| 112991 | 113009 | const char *zC /* The collating sequence name */ |
| 112992 | 113010 | ){ |
| 112993 | 113011 | Token s; |
| 112994 | 113012 | assert( zC!=0 ); |
| | @@ -123703,11 +123721,11 @@ |
| 123703 | 123721 | } |
| 123704 | 123722 | |
| 123705 | 123723 | /* Search for a constraint violation. Throw an exception if one is found. */ |
| 123706 | 123724 | sqlite3NestedParse(pParse, |
| 123707 | 123725 | "SELECT sqlite_fail('constraint failed', %d) " |
| 123708 | | - "FROM %Q.%Q WHERE (%.*s) IS NOT TRUE", |
| 123726 | + "FROM %Q.%Q WHERE (%.*s) IS FALSE", |
| 123709 | 123727 | SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, zExpr |
| 123710 | 123728 | ); |
| 123711 | 123729 | |
| 123712 | 123730 | /* Edit the SQL for the named table. */ |
| 123713 | 123731 | pCons = pFirst->z; |
| | @@ -125888,10 +125906,15 @@ |
| 125888 | 125906 | ** Close the old db and update the aDb[] slot with the new memdb |
| 125889 | 125907 | ** values. */ |
| 125890 | 125908 | sqlite3BtreeClose(pNew->pBt); |
| 125891 | 125909 | pNew->pBt = pNewBt; |
| 125892 | 125910 | pNew->pSchema = pNewSchema; |
| 125911 | + if( db->init.iDb==0 ){ |
| 125912 | + /* Clear all eponymous virtual table instances, as they are holding |
| 125913 | + ** pointers to the schema object just freed by sqlite3BtreeClose() */ |
| 125914 | + sqlite3VtabEponymousTableClearAll(db); |
| 125915 | + } |
| 125893 | 125916 | }else{ |
| 125894 | 125917 | sqlite3BtreeClose(pNewBt); |
| 125895 | 125918 | rc = SQLITE_NOMEM; |
| 125896 | 125919 | } |
| 125897 | 125920 | } |
| | @@ -140684,10 +140707,11 @@ |
| 140684 | 140707 | } |
| 140685 | 140708 | addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); |
| 140686 | 140709 | sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); |
| 140687 | 140710 | sqlite3VdbeJumpHere(v, addr1); |
| 140688 | 140711 | sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); |
| 140712 | + sqlite3MayAbort(pParse); |
| 140689 | 140713 | } |
| 140690 | 140714 | |
| 140691 | 140715 | /* Copy the new data already generated. */ |
| 140692 | 140716 | assert( pTab->nNVCol>0 || pParse->nErr>0 ); |
| 140693 | 140717 | sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); |
| | @@ -140752,10 +140776,11 @@ |
| 140752 | 140776 | }else{ |
| 140753 | 140777 | addr1 = sqlite3VdbeCurrentAddr(v); |
| 140754 | 140778 | sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v); |
| 140755 | 140779 | } |
| 140756 | 140780 | sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v); |
| 140781 | + sqlite3MayAbort(pParse); |
| 140757 | 140782 | } |
| 140758 | 140783 | }else if( IsVirtual(pTab) || withoutRowid ){ |
| 140759 | 140784 | sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); |
| 140760 | 140785 | }else{ |
| 140761 | 140786 | sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); |
| | @@ -147862,13 +147887,14 @@ |
| 147862 | 147887 | ** if one is set. If no busy handler or a different busy handler is set |
| 147863 | 147888 | ** then 0 is returned. Setting the busy_timeout to 0 or negative |
| 147864 | 147889 | ** disables the timeout. |
| 147865 | 147890 | */ |
| 147866 | 147891 | /*case PragTyp_BUSY_TIMEOUT*/ default: { |
| 147892 | + int n = 0; |
| 147867 | 147893 | assert( pPragma->ePragTyp==PragTyp_BUSY_TIMEOUT ); |
| 147868 | | - if( zRight ){ |
| 147869 | | - sqlite3_busy_timeout(db, sqlite3Atoi(zRight)); |
| 147894 | + if( zRight && sqlite3GetInt32(zRight,&n) ){ |
| 147895 | + sqlite3_busy_timeout(db, n); |
| 147870 | 147896 | } |
| 147871 | 147897 | returnSingleInt(v, db->busyTimeout); |
| 147872 | 147898 | break; |
| 147873 | 147899 | } |
| 147874 | 147900 | |
| | @@ -148450,10 +148476,11 @@ |
| 148450 | 148476 | ** schema. |
| 148451 | 148477 | */ |
| 148452 | 148478 | int rc; |
| 148453 | 148479 | u8 saved_iDb = db->init.iDb; |
| 148454 | 148480 | sqlite3_stmt *pStmt; |
| 148481 | + const char *zEnd; |
| 148455 | 148482 | TESTONLY(int rcp); /* Return code from sqlite3_prepare() */ |
| 148456 | 148483 | |
| 148457 | 148484 | assert( db->init.busy ); |
| 148458 | 148485 | db->init.iDb = iDb; |
| 148459 | 148486 | if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0 |
| | @@ -148464,11 +148491,11 @@ |
| 148464 | 148491 | } |
| 148465 | 148492 | } |
| 148466 | 148493 | db->init.orphanTrigger = 0; |
| 148467 | 148494 | db->init.azInit = (const char**)argv; |
| 148468 | 148495 | pStmt = 0; |
| 148469 | | - TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); |
| 148496 | + TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, &zEnd); |
| 148470 | 148497 | rc = db->errCode; |
| 148471 | 148498 | assert( (rc&0xFF)==(rcp&0xFF) ); |
| 148472 | 148499 | db->init.iDb = saved_iDb; |
| 148473 | 148500 | /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */ |
| 148474 | 148501 | if( SQLITE_OK!=rc ){ |
| | @@ -148480,10 +148507,12 @@ |
| 148480 | 148507 | sqlite3OomFault(db); |
| 148481 | 148508 | }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ |
| 148482 | 148509 | corruptSchema(pData, argv, sqlite3_errmsg(db)); |
| 148483 | 148510 | } |
| 148484 | 148511 | } |
| 148512 | + }else if( zEnd[0] ){ |
| 148513 | + corruptSchema(pData, argv, 0); |
| 148485 | 148514 | } |
| 148486 | 148515 | db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */ |
| 148487 | 148516 | sqlite3_finalize(pStmt); |
| 148488 | 148517 | }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ |
| 148489 | 148518 | corruptSchema(pData, argv, 0); |
| | @@ -151924,10 +151953,24 @@ |
| 151924 | 151953 | sqlite3ColumnSetColl(db, pCol, pColl->zName); |
| 151925 | 151954 | } |
| 151926 | 151955 | } |
| 151927 | 151956 | pTab->szTabRow = 1; /* Any non-zero value works */ |
| 151928 | 151957 | } |
| 151958 | + |
| 151959 | +/* |
| 151960 | +** Check the current subquery nesting depth. Return true and set an |
| 151961 | +** error if it has gone too deep. |
| 151962 | +*/ |
| 151963 | +static int checkSubqueryNestingDepth(Parse *pParse){ |
| 151964 | +#if SQLITE_MAX_EXPR_DEPTH>0 |
| 151965 | + if( pParse->nNestSel >= pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ |
| 151966 | + sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); |
| 151967 | + return 1; |
| 151968 | + } |
| 151969 | +#endif |
| 151970 | + return 0; |
| 151971 | +} |
| 151929 | 151972 | |
| 151930 | 151973 | /* |
| 151931 | 151974 | ** Given a SELECT statement, generate a Table structure that describes |
| 151932 | 151975 | ** the result set of that SELECT. |
| 151933 | 151976 | */ |
| | @@ -151935,16 +151978,11 @@ |
| 151935 | 151978 | Table *pTab; |
| 151936 | 151979 | sqlite3 *db = pParse->db; |
| 151937 | 151980 | u64 savedFlags; |
| 151938 | 151981 | |
| 151939 | 151982 | pParse->nNestSel++; |
| 151940 | | -#if SQLITE_MAX_EXPR_DEPTH>0 |
| 151941 | | - if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ |
| 151942 | | - sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); |
| 151943 | | - return 0; |
| 151944 | | - } |
| 151945 | | -#endif |
| 151983 | + if( checkSubqueryNestingDepth(pParse) ) return 0; |
| 151946 | 151984 | savedFlags = db->flags; |
| 151947 | 151985 | db->flags &= ~(u64)SQLITE_FullColNames; |
| 151948 | 151986 | db->flags |= SQLITE_ShortColNames; |
| 151949 | 151987 | sqlite3SelectPrep(pParse, pSelect, 0); |
| 151950 | 151988 | db->flags = savedFlags; |
| | @@ -152039,17 +152077,19 @@ |
| 152039 | 152077 | } |
| 152040 | 152078 | }else{ |
| 152041 | 152079 | sqlite3ExprCode(pParse, pLimit->pLeft, iLimit); |
| 152042 | 152080 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v); |
| 152043 | 152081 | VdbeComment((v, "LIMIT counter")); |
| 152082 | + sqlite3MayAbort(pParse); |
| 152044 | 152083 | sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v); |
| 152045 | 152084 | } |
| 152046 | 152085 | if( pLimit->pRight ){ |
| 152047 | 152086 | p->iOffset = iOffset = ++pParse->nMem; |
| 152048 | 152087 | pParse->nMem++; /* Allocate an extra register for limit+offset */ |
| 152049 | 152088 | sqlite3ExprCode(pParse, pLimit->pRight, iOffset); |
| 152050 | 152089 | sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v); |
| 152090 | + sqlite3MayAbort(pParse); |
| 152051 | 152091 | VdbeComment((v, "OFFSET counter")); |
| 152052 | 152092 | sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset); |
| 152053 | 152093 | VdbeComment((v, "LIMIT+OFFSET")); |
| 152054 | 152094 | } |
| 152055 | 152095 | } |
| | @@ -155187,18 +155227,17 @@ |
| 155187 | 155227 | } |
| 155188 | 155228 | return pWith; |
| 155189 | 155229 | } |
| 155190 | 155230 | |
| 155191 | 155231 | /* |
| 155192 | | -** This function checks if argument pFrom refers to a CTE declared by |
| 155232 | +** This function checks to see if argument pFrom refers to a CTE declared by |
| 155193 | 155233 | ** a WITH clause on the stack currently maintained by the parser (on the |
| 155194 | | -** pParse->pWith linked list). And if currently processing a CTE |
| 155195 | | -** CTE expression, through routine checks to see if the reference is |
| 155196 | | -** a recursive reference to the CTE. |
| 155234 | +** pParse->pWith linked list). And if currently processing a CTE expression, |
| 155235 | +** it also checks to see if the reference is a recursive reference to the CTE. |
| 155197 | 155236 | ** |
| 155198 | | -** If pFrom matches a CTE according to either of these two above, pFrom->pSTab |
| 155199 | | -** and other fields are populated accordingly. |
| 155237 | +** If pFrom matches a CTE, pFrom->pSTab and other fields are populated |
| 155238 | +** accordingly. |
| 155200 | 155239 | ** |
| 155201 | 155240 | ** Return 0 if no match is found. |
| 155202 | 155241 | ** Return 1 if a match is found. |
| 155203 | 155242 | ** Return 2 if an error condition is detected. |
| 155204 | 155243 | */ |
| | @@ -155323,10 +155362,22 @@ |
| 155323 | 155362 | } |
| 155324 | 155363 | if( (pRecTerm->selFlags & SF_Recursive)==0 ) break; |
| 155325 | 155364 | pRecTerm = pRecTerm->pPrior; |
| 155326 | 155365 | } |
| 155327 | 155366 | |
| 155367 | +#if SQLITE_MAX_EXPR_DEPTH>0 |
| 155368 | + if( pParse->nTab>=db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ |
| 155369 | + /* Bug 2026-10-04T05:35:14Z: Prevent nested CTEs from generating |
| 155370 | + ** an exponential number of cursors. The error message here will |
| 155371 | + ** be "Nested too deep", which isn't exactly correct, but it is |
| 155372 | + ** sufficient, and we don't want to use extra code space for more |
| 155373 | + ** detail on such an obscure error. */ |
| 155374 | + pParse->nNestSel = pParse->nTab; |
| 155375 | + } |
| 155376 | + pParse->nNestSel++; |
| 155377 | + if( checkSubqueryNestingDepth(pParse) ) return 2; |
| 155378 | +#endif |
| 155328 | 155379 | pCte->zCteErr = "circular reference: %s"; |
| 155329 | 155380 | pSavedWith = pParse->pWith; |
| 155330 | 155381 | pParse->pWith = pWith; |
| 155331 | 155382 | if( pSel->selFlags & SF_Recursive ){ |
| 155332 | 155383 | int rc; |
| | @@ -155347,10 +155398,14 @@ |
| 155347 | 155398 | pParse->pWith = pSavedWith; |
| 155348 | 155399 | return 2; |
| 155349 | 155400 | } |
| 155350 | 155401 | } |
| 155351 | 155402 | pParse->pWith = pWith; |
| 155403 | +#if SQLITE_MAX_EXPR_DEPTH>0 |
| 155404 | + pParse->nNestSel--; |
| 155405 | + assert( pParse->nNestSel>=0 ); |
| 155406 | +#endif |
| 155352 | 155407 | |
| 155353 | 155408 | for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); |
| 155354 | 155409 | pEList = pLeft->pEList; |
| 155355 | 155410 | if( pCte->pCols ){ |
| 155356 | 155411 | if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ |
| | @@ -156722,10 +156777,14 @@ |
| 156722 | 156777 | sqlite3PExprAddSelect(pParse, pTerm, pSub); |
| 156723 | 156778 | if( pExpr==0 ){ |
| 156724 | 156779 | pExpr = pTerm; |
| 156725 | 156780 | }else{ |
| 156726 | 156781 | pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); |
| 156782 | + } |
| 156783 | + if( pParse->nErr ){ |
| 156784 | + sqlite3ExprDelete(db, pExpr); |
| 156785 | + pExpr = 0; |
| 156727 | 156786 | } |
| 156728 | 156787 | pSub = pPrior; |
| 156729 | 156788 | } |
| 156730 | 156789 | p->pEList->a[0].pExpr = pExpr; |
| 156731 | 156790 | p->selFlags &= ~(u32)SF_Aggregate; |
| | @@ -161221,10 +161280,11 @@ |
| 161221 | 161280 | sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); |
| 161222 | 161281 | }else{ |
| 161223 | 161282 | sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid); |
| 161224 | 161283 | } |
| 161225 | 161284 | sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v); |
| 161285 | + sqlite3MayAbort(pParse); |
| 161226 | 161286 | } |
| 161227 | 161287 | |
| 161228 | 161288 | /* Compute the old pre-UPDATE content of the row being changed, if that |
| 161229 | 161289 | ** information is needed */ |
| 161230 | 161290 | if( chngPk || hasFK || pTrigger ){ |
| | @@ -163769,10 +163829,21 @@ |
| 163769 | 163829 | pTab->tabFlags |= TF_Ephemeral; |
| 163770 | 163830 | sqlite3DeleteTable(db, pTab); |
| 163771 | 163831 | pMod->pEpoTab = 0; |
| 163772 | 163832 | } |
| 163773 | 163833 | } |
| 163834 | + |
| 163835 | +/* |
| 163836 | +** Erase all eponymous virtual table instances associated with database |
| 163837 | +** handle db. |
| 163838 | +*/ |
| 163839 | +SQLITE_PRIVATE void sqlite3VtabEponymousTableClearAll(sqlite3 *db){ |
| 163840 | + HashElem *pElem; |
| 163841 | + for(pElem=sqliteHashFirst(&db->aModule); pElem; pElem=sqliteHashNext(pElem)){ |
| 163842 | + sqlite3VtabEponymousTableClear(db, (Module*)sqliteHashData(pElem)); |
| 163843 | + } |
| 163844 | +} |
| 163774 | 163845 | |
| 163775 | 163846 | /* |
| 163776 | 163847 | ** Return the ON CONFLICT resolution mode in effect for the virtual |
| 163777 | 163848 | ** table update operation currently in progress. |
| 163778 | 163849 | ** |
| | @@ -187762,14 +187833,14 @@ |
| 187762 | 187833 | #endif |
| 187763 | 187834 | |
| 187764 | 187835 | /* |
| 187765 | 187836 | ** Return zero if the given SQL string is complete - if all comments, |
| 187766 | 187837 | ** string and blob literals, and quoted identifiers have been closed and |
| 187767 | | -** if the entire string ends with ";" and possible with ";END;" if the |
| 187838 | +** if the entire string ends with ";" and possibly with ";END;" if the |
| 187768 | 187839 | ** string is a CREATE TRIGGER statement. A non-zero return indicates |
| 187769 | | -** that the string is incomplete. Bits of the return value indicate |
| 187770 | | -** what is missing and is needed to close out the statement. |
| 187840 | +** that the string is empty or incomplete. Bits of the return value |
| 187841 | +** indicate what is missing and is needed to close out the statement. |
| 187771 | 187842 | ** |
| 187772 | 187843 | ** Special handling is require for CREATE TRIGGER statements. |
| 187773 | 187844 | ** Whenever the CREATE TRIGGER keywords are seen, the statement |
| 187774 | 187845 | ** must end with ";END;". |
| 187775 | 187846 | ** |
| | @@ -187777,15 +187848,16 @@ |
| 187777 | 187848 | ** subfields, at byte boundaries: |
| 187778 | 187849 | ** |
| 187779 | 187850 | ** R = 0xwwwwwwww00xxyyzz |
| 187780 | 187851 | ** |
| 187781 | 187852 | ** In other words, zz is the least significant byte, yy is the next |
| 187782 | | -** most significant byte, xx is the third byte, wwwwwwww is a 32-bit |
| 187783 | | -** value from the middle. |
| 187853 | +** most significant byte, xx is the third byte, wwwwwwww is the upper |
| 187854 | +** four bytes of the return value. |
| 187784 | 187855 | ** |
| 187785 | 187856 | ** zz == SQLITE_OK Input is complete |
| 187786 | 187857 | ** zz == SQLITE_ERROR Input is incomplete |
| 187858 | +** zz == SQLITE_EMPTY Input contains only whitespace |
| 187787 | 187859 | ** zz == SQLITE_MISUSE Input is a NULL pointer |
| 187788 | 187860 | ** zz != 0 New values for zz may be added in the future |
| 187789 | 187861 | ** |
| 187790 | 187862 | ** yy == 0x01 Need a semicolon at the end |
| 187791 | 187863 | ** yy == 0x02 Need "END" and a semicolon |
| | @@ -187807,11 +187879,11 @@ |
| 187807 | 187879 | ** ((R>>24)&0xff)!=0 New uses for the 4th byte may be added |
| 187808 | 187880 | ** in the future |
| 187809 | 187881 | ** |
| 187810 | 187882 | ** This implementation uses a state machine with 8 states: |
| 187811 | 187883 | ** |
| 187812 | | -** (0) INVALID We have not yet seen a non-whitespace character. |
| 187884 | +** (0) NOTHING We have not yet seen a non-whitespace character. |
| 187813 | 187885 | ** |
| 187814 | 187886 | ** (1) START At the beginning or end of an SQL statement. This routine |
| 187815 | 187887 | ** returns 1 if it ends in the START state and 0 if it ends |
| 187816 | 187888 | ** in any other state. |
| 187817 | 187889 | ** |
| | @@ -187864,11 +187936,11 @@ |
| 187864 | 187936 | ** statement. This is the normal case. |
| 187865 | 187937 | */ |
| 187866 | 187938 | static const u8 trans[8][8] = { |
| 187867 | 187939 | /* Token: */ |
| 187868 | 187940 | /* State: ** SEMI WS OTHER EXPLAIN CREATE TEMP TRIGGER END */ |
| 187869 | | - /* 0 INVALID: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, |
| 187941 | + /* 0 NOTHING: */ { 1, 0, 2, 3, 4, 2, 2, 2, }, |
| 187870 | 187942 | /* 1 START: */ { 1, 1, 2, 3, 4, 2, 2, 2, }, |
| 187871 | 187943 | /* 2 NORMAL: */ { 1, 2, 2, 2, 2, 2, 2, 2, }, |
| 187872 | 187944 | /* 3 EXPLAIN: */ { 1, 3, 3, 2, 4, 2, 2, 2, }, |
| 187873 | 187945 | /* 4 CREATE: */ { 1, 4, 2, 2, 2, 4, 5, 2, }, |
| 187874 | 187946 | /* 5 TRIGGER: */ { 6, 5, 5, 5, 5, 5, 5, 5, }, |
| | @@ -187880,18 +187952,18 @@ |
| 187880 | 187952 | ** used to detect the end of a statement is much simpler |
| 187881 | 187953 | */ |
| 187882 | 187954 | static const u8 trans[3][3] = { |
| 187883 | 187955 | /* Token: */ |
| 187884 | 187956 | /* State: ** SEMI WS OTHER */ |
| 187885 | | - /* 0 INVALID: */ { 1, 0, 2, }, |
| 187957 | + /* 0 NOTHING: */ { 1, 0, 2, }, |
| 187886 | 187958 | /* 1 START: */ { 1, 1, 2, }, |
| 187887 | 187959 | /* 2 NORMAL: */ { 1, 2, 2, }, |
| 187888 | 187960 | }; |
| 187889 | 187961 | #endif /* SQLITE_OMIT_TRIGGER */ |
| 187890 | 187962 | /* Mapping state number to yy value for the return */ |
| 187891 | 187963 | static const u8 statemap[8] = { |
| 187892 | | - /* 0 INVALID */ 1, |
| 187964 | + /* 0 NOTHING */ 0, |
| 187893 | 187965 | /* 1 START */ 0, |
| 187894 | 187966 | /* 2 NORMAL */ 1, |
| 187895 | 187967 | /* 3 EXPLAIN */ 1, |
| 187896 | 187968 | /* 4 CREATE */ 1, |
| 187897 | 187969 | /* 5 TRIGGER */ 3, |
| | @@ -187925,10 +187997,11 @@ |
| 187925 | 187997 | break; |
| 187926 | 187998 | } |
| 187927 | 187999 | zSql += 2; |
| 187928 | 188000 | while( zSql[0] && (zSql[0]!='*' || zSql[1]!='/') ){ zSql++; } |
| 187929 | 188001 | if( zSql[0]==0 ){ |
| 188002 | + if( state==0 ) state = 2; |
| 187930 | 188003 | pending = '/'; |
| 187931 | 188004 | goto incomplete_finish; |
| 187932 | 188005 | } |
| 187933 | 188006 | zSql++; |
| 187934 | 188007 | token = tkWS; |
| | @@ -188042,10 +188115,11 @@ |
| 188042 | 188115 | } |
| 188043 | 188116 | state = trans[state][token]; |
| 188044 | 188117 | zSql++; |
| 188045 | 188118 | } |
| 188046 | 188119 | incomplete_finish: |
| 188120 | + if( state==0 ) return SQLITE_EMPTY; |
| 188047 | 188121 | if( state==1 ) nParen = 0; |
| 188048 | 188122 | return (i64)((((u64)nParen)<<32) | |
| 188049 | 188123 | ((u64)pending<<16) | |
| 188050 | 188124 | ((u64)statemap[state]<<8) | |
| 188051 | 188125 | (state!=1)); |
| | @@ -210496,10 +210570,11 @@ |
| 210496 | 210570 | SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ |
| 210497 | 210571 | int rc = SQLITE_OK; /* Return code */ |
| 210498 | 210572 | u64 cksum1 = 0; /* Checksum based on FTS index contents */ |
| 210499 | 210573 | u64 cksum2 = 0; /* Checksum based on %_content contents */ |
| 210500 | 210574 | sqlite3_stmt *pAllLangid = 0; /* Statement to return all language-ids */ |
| 210575 | + int bContentless = (p->zContentTbl && p->zContentTbl[0]=='\0'); |
| 210501 | 210576 | |
| 210502 | 210577 | /* This block calculates the checksum according to the FTS index. */ |
| 210503 | 210578 | rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0); |
| 210504 | 210579 | if( rc==SQLITE_OK ){ |
| 210505 | 210580 | int rc2; |
| | @@ -210515,11 +210590,11 @@ |
| 210515 | 210590 | rc2 = sqlite3_reset(pAllLangid); |
| 210516 | 210591 | if( rc==SQLITE_OK ) rc = rc2; |
| 210517 | 210592 | } |
| 210518 | 210593 | |
| 210519 | 210594 | /* This block calculates the checksum according to the %_content table */ |
| 210520 | | - if( rc==SQLITE_OK ){ |
| 210595 | + if( rc==SQLITE_OK && !bContentless ){ |
| 210521 | 210596 | sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule; |
| 210522 | 210597 | sqlite3_stmt *pStmt = 0; |
| 210523 | 210598 | char *zSql; |
| 210524 | 210599 | |
| 210525 | 210600 | zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); |
| | @@ -210573,11 +210648,11 @@ |
| 210573 | 210648 | |
| 210574 | 210649 | if( rc==SQLITE_CORRUPT_VTAB ){ |
| 210575 | 210650 | rc = SQLITE_OK; |
| 210576 | 210651 | *pbOk = 0; |
| 210577 | 210652 | }else{ |
| 210578 | | - *pbOk = (rc==SQLITE_OK && cksum1==cksum2); |
| 210653 | + *pbOk = (rc==SQLITE_OK && (bContentless || cksum1==cksum2)); |
| 210579 | 210654 | } |
| 210580 | 210655 | return rc; |
| 210581 | 210656 | } |
| 210582 | 210657 | |
| 210583 | 210658 | /* |
| | @@ -224142,11 +224217,11 @@ |
| 224142 | 224217 | continue; |
| 224143 | 224218 | } |
| 224144 | 224219 | break; |
| 224145 | 224220 | } |
| 224146 | 224221 | if( geopolySkipSpace(&s)==']' |
| 224147 | | - && s.nVertex>=4 |
| 224222 | + && s.nVertex>=4 && s.nVertex<16777216 |
| 224148 | 224223 | && s.a[0]==s.a[s.nVertex*2-2] |
| 224149 | 224224 | && s.a[1]==s.a[s.nVertex*2-1] |
| 224150 | 224225 | && (s.z++, geopolySkipSpace(&s)==0) |
| 224151 | 224226 | ){ |
| 224152 | 224227 | GeoPoly *pOut; |
| | @@ -224479,11 +224554,11 @@ |
| 224479 | 224554 | sqlite3_value **argv |
| 224480 | 224555 | ){ |
| 224481 | 224556 | double x = sqlite3_value_double(argv[0]); |
| 224482 | 224557 | double y = sqlite3_value_double(argv[1]); |
| 224483 | 224558 | double r = sqlite3_value_double(argv[2]); |
| 224484 | | - int n = sqlite3_value_int(argv[3]); |
| 224559 | + i64 n = sqlite3_value_int64(argv[3]); |
| 224485 | 224560 | int i; |
| 224486 | 224561 | GeoPoly *p; |
| 224487 | 224562 | (void)argc; |
| 224488 | 224563 | |
| 224489 | 224564 | if( n<3 || r<=0.0 || r>=1e300 ) return; |
| | @@ -237743,10 +237818,37 @@ |
| 237743 | 237818 | if( pzErrmsg && rc!=SQLITE_OK ){ |
| 237744 | 237819 | *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); |
| 237745 | 237820 | } |
| 237746 | 237821 | return rc; |
| 237747 | 237822 | } |
| 237823 | + |
| 237824 | +/* |
| 237825 | +** Prepare the statement specified by printf format zFmt and its trailing |
| 237826 | +** arguments. |
| 237827 | +*/ |
| 237828 | +static void sessionPrepareMprintf( |
| 237829 | + int *pRc, |
| 237830 | + sqlite3 *db, |
| 237831 | + sqlite3_stmt **pp, |
| 237832 | + char **pzErrmsg, |
| 237833 | + const char *zFmt, |
| 237834 | + ... |
| 237835 | +){ |
| 237836 | + if( *pRc==SQLITE_OK ){ |
| 237837 | + char *zSql; |
| 237838 | + va_list ap; |
| 237839 | + va_start(ap, zFmt); |
| 237840 | + zSql = sqlite3_vmprintf(zFmt, ap); |
| 237841 | + if( zSql==0 ){ |
| 237842 | + *pRc = SQLITE_NOMEM; |
| 237843 | + }else{ |
| 237844 | + *pRc = sessionPrepare(db, pp, pzErrmsg, zSql); |
| 237845 | + sqlite3_free(zSql); |
| 237846 | + } |
| 237847 | + va_end(ap); |
| 237848 | + } |
| 237849 | +} |
| 237748 | 237850 | |
| 237749 | 237851 | /* |
| 237750 | 237852 | ** Formulate and prepare a SELECT statement to retrieve a row from table |
| 237751 | 237853 | ** zTab in database zDb based on its primary key. i.e. |
| 237752 | 237854 | ** |
| | @@ -240147,165 +240249,219 @@ |
| 240147 | 240249 | |
| 240148 | 240250 | return rc; |
| 240149 | 240251 | } |
| 240150 | 240252 | |
| 240151 | 240253 | /* |
| 240152 | | -** Check if table zTab in the "main" database of db is a WITHOUT ROWID |
| 240153 | | -** table. |
| 240254 | +** Buffer aUnique[] is pApply->nCol entries in size. This function sets |
| 240255 | +** aUnique[i] to true if column i of table zTab in the "main" database |
| 240256 | +** of db is part of at least one UNIQUE constraint, or to false otherwise. |
| 240154 | 240257 | ** |
| 240155 | | -** If no error occurs, return SQLITE_OK and set output variable (*pbWR) to |
| 240156 | | -** true if zTab is a WITHOUT ROWID table, or false otherwise. Or, if an |
| 240157 | | -** error does occur, return an SQLite error code. The final value of (*pbWR) |
| 240158 | | -** is undefined in this case. |
| 240258 | +** If the table has a unique index on an expression, or a partial unique |
| 240259 | +** index, all entries of aUnique[] are set to true. |
| 240260 | +** |
| 240261 | +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. |
| 240159 | 240262 | */ |
| 240160 | | -static int sessionTableIsWithoutRowid(sqlite3 *db, const char *zTab, int *pbWR){ |
| 240161 | | - sqlite3_stmt *pList = 0; |
| 240162 | | - char *zSql = 0; |
| 240263 | +static int sessionUniqueColumns( |
| 240264 | + sqlite3 *db, /* Database handle */ |
| 240265 | + const char *zTab, /* Table name */ |
| 240266 | + SessionApplyCtx *pApply, /* Apply context */ |
| 240267 | + u8 *aUnique /* OUT: Array of pApply->nCol flags */ |
| 240268 | +){ |
| 240269 | + sqlite3_stmt *pList = 0; /* PRAGMA index_list */ |
| 240163 | 240270 | int rc = SQLITE_OK; |
| 240164 | 240271 | |
| 240165 | | - zSql = sqlite3_mprintf("PRAGMA table_list = %Q", zTab); |
| 240166 | | - if( zSql==0 ){ |
| 240167 | | - rc = SQLITE_NOMEM; |
| 240168 | | - }else{ |
| 240169 | | - rc = sqlite3_prepare_v2(db, zSql, -1, &pList, 0); |
| 240170 | | - sqlite3_free(zSql); |
| 240171 | | - } |
| 240172 | | - |
| 240173 | | - if( rc==SQLITE_OK ){ |
| 240174 | | - sqlite3_step(pList); |
| 240175 | | - *pbWR = sqlite3_column_int(pList, 4); |
| 240272 | + /* Ordinary PRAGMA statements are used here instead of the equivalent |
| 240273 | + ** table-valued functions (pragma_index_list() etc.) so that this works |
| 240274 | + ** in builds with SQLITE_OMIT_VIRTUALTABLE defined. */ |
| 240275 | + memset(aUnique, 0, pApply->nCol); |
| 240276 | + sessionPrepareMprintf(&rc, db, &pList, &pApply->zErr, |
| 240277 | + "PRAGMA main.index_list(%Q)", zTab |
| 240278 | + ); |
| 240279 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ |
| 240280 | + /* Columns of PRAGMA index_list are (seq, name, unique, origin, partial) */ |
| 240281 | + const char *zIdx = (const char*)sqlite3_column_text(pList, 1); |
| 240282 | + int bUnique = sqlite3_column_int(pList, 2); |
| 240283 | + int bPartial = sqlite3_column_int(pList, 4); |
| 240284 | + sqlite3_stmt *pInfo = 0; /* PRAGMA index_xinfo */ |
| 240285 | + |
| 240286 | + if( bUnique==0 ) continue; |
| 240287 | + sessionPrepareMprintf(&rc, db, &pInfo, &pApply->zErr, |
| 240288 | + "PRAGMA main.index_xinfo(%Q)", zIdx |
| 240289 | + ); |
| 240290 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pInfo) ){ |
| 240291 | + /* Columns of PRAGMA index_xinfo are (seqno, cid, name, desc, coll, key)*/ |
| 240292 | + int iCid = sqlite3_column_int(pInfo, 1); |
| 240293 | + const char *zCol = (const char*)sqlite3_column_text(pInfo, 2); |
| 240294 | + int bKey = sqlite3_column_int(pInfo, 5); |
| 240295 | + int ii; |
| 240296 | + if( bKey==0 ) continue; |
| 240297 | + for(ii=0; ii<pApply->nCol; ii++){ |
| 240298 | + if( bPartial |
| 240299 | + || iCid==-2 |
| 240300 | + || (zCol && 0==sqlite3_stricmp(zCol, pApply->azCol[ii])) |
| 240301 | + ){ |
| 240302 | + aUnique[ii] = 1; |
| 240303 | + } |
| 240304 | + } |
| 240305 | + } |
| 240306 | + if( rc==SQLITE_OK ){ |
| 240307 | + rc = sqlite3_finalize(pInfo); |
| 240308 | + }else{ |
| 240309 | + sqlite3_finalize(pInfo); |
| 240310 | + } |
| 240311 | + } |
| 240312 | + if( rc==SQLITE_OK ){ |
| 240176 | 240313 | rc = sqlite3_finalize(pList); |
| 240314 | + }else{ |
| 240315 | + sqlite3_finalize(pList); |
| 240177 | 240316 | } |
| 240178 | 240317 | |
| 240179 | 240318 | return rc; |
| 240180 | 240319 | } |
| 240181 | 240320 | |
| 240182 | 240321 | /* |
| 240183 | | -** Iterator pUp points to an UPDATE change. This function deletes the |
| 240184 | | -** affected row from the database and creates an INSERT statement that |
| 240185 | | -** may be used to reinsert the row as it is after the UPDATE change |
| 240186 | | -** has been applied. |
| 240322 | +** Iterator pUp points to an UPDATE change. This function updates the |
| 240323 | +** affected row to set each column modified by the UPDATE change that |
| 240324 | +** is also part of at least one UNIQUE constraint to a "random" value, |
| 240325 | +** and creates another UPDATE statement that may be used to later set |
| 240326 | +** all columns modified by pUp to the actual values required by pUp. |
| 240187 | 240327 | ** |
| 240188 | | -** If successful, SQLITE_OK is returned and output variable (*ppInsert) |
| 240189 | | -** is left pointing to a prepared INSERT statement. It is the responsibility |
| 240328 | +** Each random value has the same type as the final value required by |
| 240329 | +** pUp for the same column: |
| 240330 | +** |
| 240331 | +** NULL -> NULL |
| 240332 | +** INTEGER -> random() |
| 240333 | +** REAL -> random() |
| 240334 | +** TEXT -> CAST(random() AS TEXT) |
| 240335 | +** BLOB -> unhex(hex(random())) |
| 240336 | +** |
| 240337 | +** If none of the columns modified by pUp are part of a UNIQUE constraint, |
| 240338 | +** then SQLITE_CONSTRAINT is returned. |
| 240339 | +** |
| 240340 | +** If successful, SQLITE_OK is returned and output variable (*ppUpdate) |
| 240341 | +** is left pointing to a prepared UPDATE statement. It is the responsibility |
| 240190 | 240342 | ** of the caller to eventually free this statement using sqlite3_finalize(). |
| 240191 | | -** Or, if an error occurs, an SQLite error code is returned and (*ppInsert) |
| 240343 | +** Or, if an error occurs, an SQLite error code is returned and (*ppUpdate) |
| 240192 | 240344 | ** set to NULL. pApply->zErr may be set to an error message in this case. |
| 240345 | +** Except - it is guaranteed that pApply->zErr is not set if SQLITE_CONSTRAINT |
| 240346 | +** is returned. |
| 240193 | 240347 | */ |
| 240194 | | -static int sessionUpdateToDeleteInsert( |
| 240348 | +static int sessionUpdateToUpdate( |
| 240195 | 240349 | sqlite3 *db, /* Database to write to */ |
| 240196 | 240350 | const char *zTab, /* Table name */ |
| 240197 | 240351 | SessionApplyCtx *pApply, /* Apply context */ |
| 240198 | 240352 | sqlite3_changeset_iter *pUp, /* Iterator pointing to UPDATE change */ |
| 240199 | | - sqlite3_stmt **ppInsert /* OUT: INSERT statement */ |
| 240200 | | -){ |
| 240201 | | - sqlite3_stmt *pRet = 0; /* The INSERT statement */ |
| 240202 | | - sqlite3_stmt *pSelect = 0; /* SELECT to read current values of row */ |
| 240203 | | - int rc = SQLITE_OK; |
| 240204 | | - int bWR = 0; |
| 240205 | | - |
| 240206 | | - rc = sessionTableIsWithoutRowid(db, zTab, &bWR); |
| 240207 | | - if( rc==SQLITE_OK ){ |
| 240208 | | - char *zSelect = 0; |
| 240209 | | - char *zInsert = 0; |
| 240210 | | - SessionBuffer cols = {0, 0, 0}; |
| 240211 | | - SessionBuffer insbind = {0, 0, 0}; |
| 240212 | | - SessionBuffer pkcols = {0, 0, 0}; |
| 240213 | | - SessionBuffer selbind = {0, 0, 0}; |
| 240214 | | - |
| 240215 | | - const char *zComma = ""; |
| 240216 | | - const char *zComma2 = ""; |
| 240217 | | - int ii; |
| 240218 | | - for(ii=0; ii<pApply->nCol; ii++){ |
| 240219 | | - sessionAppendStr(&cols, zComma, &rc); |
| 240220 | | - sessionAppendIdent(&cols, pApply->azCol[ii], &rc); |
| 240221 | | - sessionAppendStr(&insbind, zComma, &rc); |
| 240222 | | - sessionAppendStr(&insbind, "?", &rc); |
| 240223 | | - zComma = ", "; |
| 240224 | | - |
| 240225 | | - if( pApply->abPK[ii] ){ |
| 240226 | | - sessionAppendStr(&pkcols, zComma2, &rc); |
| 240227 | | - sessionAppendIdent(&pkcols, pApply->azCol[ii], &rc); |
| 240228 | | - sessionAppendStr(&selbind, zComma2, &rc); |
| 240229 | | - sessionAppendPrintf(&selbind, &rc, "?%d", ii+1); |
| 240230 | | - zComma2 = ", "; |
| 240231 | | - } |
| 240232 | | - } |
| 240233 | | - if( bWR==0 ){ |
| 240234 | | - sessionAppendStr(&cols, zComma, &rc); |
| 240235 | | - sessionAppendStr(&cols, SESSIONS_ROWID, &rc); |
| 240236 | | - sessionAppendStr(&insbind, zComma, &rc); |
| 240237 | | - sessionAppendStr(&insbind, "?", &rc); |
| 240238 | | - } |
| 240239 | | - |
| 240240 | | - if( rc==SQLITE_OK ){ |
| 240241 | | - zSelect = sqlite3_mprintf("SELECT %s FROM %Q WHERE (%s) IS (%s)", |
| 240242 | | - cols.aBuf, zTab, pkcols.aBuf, selbind.aBuf |
| 240243 | | - ); |
| 240244 | | - if( zSelect==0 ) rc = SQLITE_NOMEM; |
| 240245 | | - } |
| 240246 | | - if( rc==SQLITE_OK ){ |
| 240247 | | - zInsert = sqlite3_mprintf("INSERT INTO %Q(%s) VALUES(%s)", |
| 240248 | | - zTab, cols.aBuf, insbind.aBuf |
| 240249 | | - ); |
| 240250 | | - if( zInsert==0 ) rc = SQLITE_NOMEM; |
| 240251 | | - } |
| 240252 | | - |
| 240253 | | - if( rc==SQLITE_OK ){ |
| 240254 | | - rc = sessionPrepare(db, &pSelect, &pApply->zErr, zSelect); |
| 240255 | | - } |
| 240256 | | - if( rc==SQLITE_OK ){ |
| 240257 | | - rc = sessionPrepare(db, &pRet, &pApply->zErr, zInsert); |
| 240258 | | - } |
| 240259 | | - |
| 240260 | | - sqlite3_free(zSelect); |
| 240261 | | - sqlite3_free(zInsert); |
| 240262 | | - sqlite3_free(cols.aBuf); |
| 240263 | | - sqlite3_free(insbind.aBuf); |
| 240264 | | - sqlite3_free(pkcols.aBuf); |
| 240265 | | - sqlite3_free(selbind.aBuf); |
| 240266 | | - } |
| 240267 | | - |
| 240268 | | - if( rc==SQLITE_OK ){ |
| 240269 | | - rc = sessionBindRow( |
| 240270 | | - pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pSelect |
| 240271 | | - ); |
| 240272 | | - } |
| 240273 | | - |
| 240274 | | - if( rc==SQLITE_OK && sqlite3_step(pSelect)==SQLITE_ROW ){ |
| 240275 | | - int iCol; |
| 240276 | | - for(iCol=0; iCol<pApply->nCol; iCol++){ |
| 240277 | | - sqlite3_value *pVal = pUp->apValue[iCol+pApply->nCol]; |
| 240278 | | - if( pVal==0 ){ |
| 240279 | | - pVal = sqlite3_column_value(pSelect, iCol); |
| 240280 | | - } |
| 240281 | | - rc = sqlite3_bind_value(pRet, iCol+1, pVal); |
| 240282 | | - } |
| 240283 | | - if( bWR==0 ){ |
| 240284 | | - sqlite3_bind_int64(pRet, iCol+1, sqlite3_column_int64(pSelect, iCol)); |
| 240285 | | - } |
| 240286 | | - } |
| 240287 | | - sessionFinalizeStmt(pSelect, &rc); |
| 240288 | | - |
| 240289 | | - /* Delete the row from the database. */ |
| 240290 | | - if( rc==SQLITE_OK ){ |
| 240291 | | - rc = sessionBindRow( |
| 240292 | | - pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pApply->pDelete |
| 240293 | | - ); |
| 240294 | | - sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1); |
| 240295 | | - } |
| 240296 | | - if( rc==SQLITE_OK ){ |
| 240297 | | - sqlite3_step(pApply->pDelete); |
| 240298 | | - rc = sqlite3_reset(pApply->pDelete); |
| 240299 | | - } |
| 240353 | + sqlite3_stmt **ppUpdate /* OUT: UPDATE statement */ |
| 240354 | +){ |
| 240355 | + sqlite3_stmt *pRet = 0; /* UPDATE to set the final values */ |
| 240356 | + sqlite3_stmt *pRand = 0; /* UPDATE to set random values */ |
| 240357 | + int rc = SQLITE_OK; |
| 240358 | + u8 *aUnique = 0; /* aUnique[i] true if col i is UNIQUE */ |
| 240359 | + SessionBuffer randset = {0, 0, 0}; |
| 240360 | + SessionBuffer upset = {0, 0, 0}; |
| 240361 | + SessionBuffer where = {0, 0, 0}; |
| 240362 | + int ii; |
| 240363 | + |
| 240364 | + aUnique = (u8*)sqlite3_malloc64(pApply->nCol); |
| 240365 | + if( aUnique==0 ){ |
| 240366 | + rc = SQLITE_NOMEM; |
| 240367 | + }else{ |
| 240368 | + rc = sessionUniqueColumns(db, zTab, pApply, aUnique); |
| 240369 | + } |
| 240370 | + |
| 240371 | + /* Assuming a table structure like this: |
| 240372 | + ** |
| 240373 | + ** CREATE TABLE x(a, b UNIQUE, c, d UNIQUE, e, PRIMARY KEY(a, c)); |
| 240374 | + ** |
| 240375 | + ** and an UPDATE change that sets column b to an integer, column d to |
| 240376 | + ** a text value and column e to any value, the two statements prepared |
| 240377 | + ** are: |
| 240378 | + ** |
| 240379 | + ** UPDATE main.x SET b = random(), d = CAST(random() AS TEXT) |
| 240380 | + ** WHERE a IS ?1 AND c IS ?3 |
| 240381 | + ** UPDATE main.x SET b = ?2, d = ?4, e = ?5 WHERE a IS ?1 AND c IS ?3 |
| 240382 | + */ |
| 240383 | + for(ii=0; rc==SQLITE_OK && ii<pApply->nCol; ii++){ |
| 240384 | + sqlite3_value *pNew = 0; |
| 240385 | + if( pApply->abPK[ii] ){ |
| 240386 | + if( where.nBuf>0 ) sessionAppendStr(&where, " AND ", &rc); |
| 240387 | + sessionAppendIdent(&where, pApply->azCol[ii], &rc); |
| 240388 | + sessionAppendPrintf(&where, &rc, " IS ?%d", ii+1); |
| 240389 | + }else if( (pNew = sessionChangesetNew(pUp, ii))!=0 ){ |
| 240390 | + if( aUnique[ii] ){ |
| 240391 | + const char *zRand = 0; |
| 240392 | + switch( sqlite3_value_type(pNew) ){ |
| 240393 | + case SQLITE_NULL: zRand = "NULL"; break; |
| 240394 | + case SQLITE_TEXT: zRand = "CAST(random() AS TEXT)"; break; |
| 240395 | + case SQLITE_BLOB: zRand = "unhex(hex(random()))"; break; |
| 240396 | + default: zRand = "random()"; break; |
| 240397 | + } |
| 240398 | + if( randset.nBuf>0 ) sessionAppendStr(&randset, ", ", &rc); |
| 240399 | + sessionAppendIdent(&randset, pApply->azCol[ii], &rc); |
| 240400 | + sessionAppendStr(&randset, " = ", &rc); |
| 240401 | + sessionAppendStr(&randset, zRand, &rc); |
| 240402 | + } |
| 240403 | + if( upset.nBuf>0 ) sessionAppendStr(&upset, ", ", &rc); |
| 240404 | + sessionAppendIdent(&upset, pApply->azCol[ii], &rc); |
| 240405 | + sessionAppendPrintf(&upset, &rc, " = ?%d", ii+1); |
| 240406 | + } |
| 240407 | + } |
| 240408 | + |
| 240409 | + if( rc==SQLITE_OK && randset.nBuf==0 ){ |
| 240410 | + /* None of the columns modified by this change are part of a UNIQUE |
| 240411 | + ** constraint. So setting them to random values cannot help resolve |
| 240412 | + ** a constraint conflict. Report this as a constraint failure. */ |
| 240413 | + rc = SQLITE_CONSTRAINT; |
| 240414 | + } |
| 240415 | + |
| 240416 | + sessionPrepareMprintf(&rc, db, &pRand, &pApply->zErr, |
| 240417 | + "UPDATE main.\"%w\" SET %s WHERE %s", |
| 240418 | + zTab, (char*)randset.aBuf, (char*)where.aBuf |
| 240419 | + ); |
| 240420 | + sessionPrepareMprintf(&rc, db, &pRet, &pApply->zErr, |
| 240421 | + "UPDATE main.\"%w\" SET %s WHERE %s", |
| 240422 | + zTab, (char*)upset.aBuf, (char*)where.aBuf |
| 240423 | + ); |
| 240424 | + |
| 240425 | + /* Bind the PK values to both statements, and the new.* values to pRet. */ |
| 240426 | + if( rc==SQLITE_OK ){ |
| 240427 | + rc = sessionBindRow( |
| 240428 | + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pRand |
| 240429 | + ); |
| 240430 | + } |
| 240431 | + if( rc==SQLITE_OK ){ |
| 240432 | + rc = sessionBindRow( |
| 240433 | + pUp, sqlite3changeset_old, pApply->nCol, pApply->abPK, pRet |
| 240434 | + ); |
| 240435 | + } |
| 240436 | + for(ii=0; rc==SQLITE_OK && ii<pApply->nCol; ii++){ |
| 240437 | + sqlite3_value *pNew = sessionChangesetNew(pUp, ii); |
| 240438 | + if( pApply->abPK[ii]==0 && pNew ){ |
| 240439 | + rc = sessionBindValue(pRet, ii+1, pNew); |
| 240440 | + } |
| 240441 | + } |
| 240442 | + |
| 240443 | + /* Evaluate the statement to set each modified column of the row to a random |
| 240444 | + ** value. If this fails with a constraint error, SQLITE_CONSTRAINT is |
| 240445 | + ** returned to the caller, but pApply->zErr is not set. */ |
| 240446 | + if( rc==SQLITE_OK ){ |
| 240447 | + sqlite3_step(pRand); |
| 240448 | + rc = sqlite3_reset(pRand); |
| 240449 | + } |
| 240450 | + sqlite3_finalize(pRand); |
| 240300 | 240451 | |
| 240301 | 240452 | if( rc!=SQLITE_OK ){ |
| 240302 | 240453 | sqlite3_finalize(pRet); |
| 240303 | 240454 | pRet = 0; |
| 240304 | 240455 | } |
| 240456 | + *ppUpdate = pRet; |
| 240305 | 240457 | |
| 240306 | | - *ppInsert = pRet; |
| 240458 | + sqlite3_free(aUnique); |
| 240459 | + sqlite3_free(randset.aBuf); |
| 240460 | + sqlite3_free(upset.aBuf); |
| 240461 | + sqlite3_free(where.aBuf); |
| 240462 | + |
| 240307 | 240463 | return rc; |
| 240308 | 240464 | } |
| 240309 | 240465 | |
| 240310 | 240466 | /* |
| 240311 | 240467 | ** Retry the changes accumulated in the pApply->constraints buffer. The |
| | @@ -240318,18 +240474,21 @@ |
| 240318 | 240474 | ** is repeated until no further progress can be made. |
| 240319 | 240475 | ** |
| 240320 | 240476 | ** 2) For each UPDATE change in the buffer, try the following in a |
| 240321 | 240477 | ** savepoint transaction: |
| 240322 | 240478 | ** |
| 240323 | | -** a) DELETE the affected row, |
| 240479 | +** a) UPDATE the affected row, setting each column modified by the |
| 240480 | +** UPDATE change to a random value, |
| 240324 | 240481 | ** b) Attempt step (1) with remaining changes, |
| 240325 | | -** c) Attempt to INSERT a row equivalent to the one that would be |
| 240326 | | -** created by applying this UPDATE change. |
| 240482 | +** c) Attempt to UPDATE the affected row again, this time setting |
| 240483 | +** each modified column to the value required by the UPDATE change. |
| 240327 | 240484 | ** |
| 240328 | | -** If the INSERT in (c) succeeds, the savepoint is committed and all |
| 240485 | +** If both (a) and (c) succeed, the savepoint is committed and all |
| 240329 | 240486 | ** successfully applied changes are removed from the buffer. Step (2) |
| 240330 | | -** is then repeated. |
| 240487 | +** is then repeated. Otherwise, if either (a) or (c) fails with |
| 240488 | +** SQLITE_CONSTRAINT, the savepoint is rolled back and the next UPDATE |
| 240489 | +** in the buffer is tried. |
| 240331 | 240490 | ** |
| 240332 | 240491 | ** 3) Once step (2) has been attempted for each UPDATE in the change, |
| 240333 | 240492 | ** a final attempt is made to apply each remaining change. This time, |
| 240334 | 240493 | ** if an SQLITE_CONSTRAINT error is encountered, the conflict handler |
| 240335 | 240494 | ** is invoked and the user has to decide whether to omit the change |
| | @@ -240364,12 +240523,13 @@ |
| 240364 | 240523 | |
| 240365 | 240524 | /* Step (2) */ |
| 240366 | 240525 | while( rc==SQLITE_OK && pApply->constraints.nBuf && !pApply->bNoUpdateLoop ){ |
| 240367 | 240526 | SessionBuffer cons = {0, 0, 0}; |
| 240368 | 240527 | sqlite3_changeset_iter *pUp = 0; |
| 240369 | | - sqlite3_stmt *pInsert = 0; |
| 240528 | + sqlite3_stmt *pUpdate = 0; |
| 240370 | 240529 | int iSkip = 0; |
| 240530 | + int bConstraint = 0; /* True if an SQLITE_CONSTRAINT occurs */ |
| 240371 | 240531 | |
| 240372 | 240532 | rc = sessionRetryIterInit( |
| 240373 | 240533 | &pApply->constraints, bPatchset, zTab, pApply, &pUp |
| 240374 | 240534 | ); |
| 240375 | 240535 | if( rc==SQLITE_OK ){ |
| | @@ -240380,19 +240540,26 @@ |
| 240380 | 240540 | iSkip++; |
| 240381 | 240541 | } |
| 240382 | 240542 | if( iThis==iUpdate ){ |
| 240383 | 240543 | rc = sqlite3_exec(db, "SAVEPOINT update_op", 0, 0, 0); |
| 240384 | 240544 | if( rc==SQLITE_OK ){ |
| 240385 | | - rc = sessionUpdateToDeleteInsert(db, zTab, pApply, pUp, &pInsert); |
| 240545 | + rc = sessionUpdateToUpdate(db, zTab, pApply, pUp, &pUpdate); |
| 240546 | + if( (rc&0xff)==SQLITE_CONSTRAINT ){ |
| 240547 | + bConstraint = 1; |
| 240548 | + rc = SQLITE_OK; |
| 240549 | + } |
| 240386 | 240550 | } |
| 240387 | 240551 | } |
| 240388 | 240552 | sqlite3changeset_finalize(pUp); |
| 240389 | 240553 | if( iThis!=iUpdate ) break; |
| 240390 | 240554 | } |
| 240391 | 240555 | |
| 240392 | 240556 | if( rc==SQLITE_OK ){ |
| 240393 | 240557 | cons = pApply->constraints; |
| 240558 | + if( bConstraint ){ |
| 240559 | + memset(&pApply->constraints, 0, sizeof(SessionBuffer)); |
| 240560 | + } |
| 240394 | 240561 | |
| 240395 | 240562 | while( rc==SQLITE_OK && pApply->constraints.nBuf>0 ){ |
| 240396 | 240563 | SessionBuffer app = pApply->constraints; |
| 240397 | 240564 | memset(&pApply->constraints, 0, sizeof(SessionBuffer)); |
| 240398 | 240565 | rc = sessionApplyRetryBuffer( |
| | @@ -240408,13 +240575,20 @@ |
| 240408 | 240575 | } |
| 240409 | 240576 | } |
| 240410 | 240577 | |
| 240411 | 240578 | iUpdate++; |
| 240412 | 240579 | if( rc==SQLITE_OK ){ |
| 240413 | | - sqlite3_step(pInsert); |
| 240414 | | - rc = sqlite3_finalize(pInsert); |
| 240415 | | - if( (rc&0xff)==SQLITE_CONSTRAINT ){ |
| 240580 | + if( bConstraint==0 ){ |
| 240581 | + sqlite3_step(pUpdate); |
| 240582 | + rc = sqlite3_finalize(pUpdate); |
| 240583 | + pUpdate = 0; |
| 240584 | + if( (rc&0xff)==SQLITE_CONSTRAINT ){ |
| 240585 | + bConstraint = 1; |
| 240586 | + rc = SQLITE_OK; |
| 240587 | + } |
| 240588 | + } |
| 240589 | + if( bConstraint ){ |
| 240416 | 240590 | rc = sqlite3_exec(db, "ROLLBACK TO update_op", 0, 0, 0); |
| 240417 | 240591 | sqlite3_free(pApply->constraints.aBuf); |
| 240418 | 240592 | pApply->constraints = cons; |
| 240419 | 240593 | memset(&cons, 0, sizeof(cons)); |
| 240420 | 240594 | }else if( rc==SQLITE_OK ){ |
| | @@ -240421,13 +240595,12 @@ |
| 240421 | 240595 | iUpdate = 0; |
| 240422 | 240596 | } |
| 240423 | 240597 | if( rc==SQLITE_OK ){ |
| 240424 | 240598 | rc = sqlite3_exec(db, "RELEASE update_op", 0, 0, 0); |
| 240425 | 240599 | } |
| 240426 | | - }else{ |
| 240427 | | - sqlite3_finalize(pInsert); |
| 240428 | 240600 | } |
| 240601 | + sqlite3_finalize(pUpdate); |
| 240429 | 240602 | |
| 240430 | 240603 | sqlite3_free(cons.aBuf); |
| 240431 | 240604 | } |
| 240432 | 240605 | |
| 240433 | 240606 | /* Step (3) */ |
| | @@ -265203,11 +265376,11 @@ |
| 265203 | 265376 | int nArg, /* Number of args */ |
| 265204 | 265377 | sqlite3_value **apUnused /* Function arguments */ |
| 265205 | 265378 | ){ |
| 265206 | 265379 | assert( nArg==0 ); |
| 265207 | 265380 | UNUSED_PARAM2(nArg, apUnused); |
| 265208 | | - sqlite3_result_text(pCtx, "fts5: 2026-10-01 11:21:02 92709f54d4c58cf174f305b58971a01878af313157a11549b588a25216701f5c", -1, SQLITE_TRANSIENT); |
| 265381 | + sqlite3_result_text(pCtx, "fts5: 2026-10-05 14:22:13 4bfc6e53a95d710b7f40fa9c80d8cdd1df50d69ed8614e9800f7e6a1ca5a3c29", -1, SQLITE_TRANSIENT); |
| 265209 | 265382 | } |
| 265210 | 265383 | |
| 265211 | 265384 | /* |
| 265212 | 265385 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 265213 | 265386 | ** |
| 265214 | 265387 | |