| | @@ -1,8 +1,8 @@ |
| 1 | 1 | /****************************************************************************** |
| 2 | 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | | -** version 3.44.2. By combining all the individual C code files into this |
| 3 | +** version 3.45.0. By combining all the individual C code files into this |
| 4 | 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | 8 | ** translation unit. |
| | @@ -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 | | -** ebead0e7230cd33bcec9f95d2183069565b9. |
| 21 | +** 27d4a89a5ff96b7b7fc5dc9650e1269f7c7e. |
| 22 | 22 | */ |
| 23 | 23 | #define SQLITE_CORE 1 |
| 24 | 24 | #define SQLITE_AMALGAMATION 1 |
| 25 | 25 | #ifndef SQLITE_PRIVATE |
| 26 | 26 | # define SQLITE_PRIVATE static |
| | @@ -457,13 +457,13 @@ |
| 457 | 457 | ** |
| 458 | 458 | ** See also: [sqlite3_libversion()], |
| 459 | 459 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 460 | 460 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 461 | 461 | */ |
| 462 | | -#define SQLITE_VERSION "3.44.2" |
| 463 | | -#define SQLITE_VERSION_NUMBER 3044002 |
| 464 | | -#define SQLITE_SOURCE_ID "2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f" |
| 462 | +#define SQLITE_VERSION "3.45.0" |
| 463 | +#define SQLITE_VERSION_NUMBER 3045000 |
| 464 | +#define SQLITE_SOURCE_ID "2023-12-14 16:34:47 27d4a89a5ff96b7b7fc5dc9650e1269f7c7edf91de9b9aafce40be9ecc8b95e9" |
| 465 | 465 | |
| 466 | 466 | /* |
| 467 | 467 | ** CAPI3REF: Run-Time Library Version Numbers |
| 468 | 468 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 469 | 469 | ** |
| | @@ -4265,19 +4265,21 @@ |
| 4265 | 4265 | ** <li> sqlite3_errmsg16() |
| 4266 | 4266 | ** <li> sqlite3_error_offset() |
| 4267 | 4267 | ** </ul> |
| 4268 | 4268 | ** |
| 4269 | 4269 | ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language |
| 4270 | | -** text that describes the error, as either UTF-8 or UTF-16 respectively. |
| 4270 | +** text that describes the error, as either UTF-8 or UTF-16 respectively, |
| 4271 | +** or NULL if no error message is available. |
| 4271 | 4272 | ** (See how SQLite handles [invalid UTF] for exceptions to this rule.) |
| 4272 | 4273 | ** ^(Memory to hold the error message string is managed internally. |
| 4273 | 4274 | ** The application does not need to worry about freeing the result. |
| 4274 | 4275 | ** However, the error string might be overwritten or deallocated by |
| 4275 | 4276 | ** subsequent calls to other SQLite interface functions.)^ |
| 4276 | 4277 | ** |
| 4277 | | -** ^The sqlite3_errstr() interface returns the English-language text |
| 4278 | | -** that describes the [result code], as UTF-8. |
| 4278 | +** ^The sqlite3_errstr(E) interface returns the English-language text |
| 4279 | +** that describes the [result code] E, as UTF-8, or NULL if E is not an |
| 4280 | +** result code for which a text error message is available. |
| 4279 | 4281 | ** ^(Memory to hold the error message string is managed internally |
| 4280 | 4282 | ** and must not be freed by the application)^. |
| 4281 | 4283 | ** |
| 4282 | 4284 | ** ^If the most recent error references a specific token in the input |
| 4283 | 4285 | ** SQL, the sqlite3_error_offset() interface returns the byte offset |
| | @@ -8609,10 +8611,11 @@ |
| 8609 | 8611 | #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 |
| 8610 | 8612 | #define SQLITE_TESTCTRL_PENDING_BYTE 11 |
| 8611 | 8613 | #define SQLITE_TESTCTRL_ASSERT 12 |
| 8612 | 8614 | #define SQLITE_TESTCTRL_ALWAYS 13 |
| 8613 | 8615 | #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ |
| 8616 | +#define SQLITE_TESTCTRL_JSON_SELFCHECK 14 |
| 8614 | 8617 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 |
| 8615 | 8618 | #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ |
| 8616 | 8619 | #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ |
| 8617 | 8620 | #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 |
| 8618 | 8621 | #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 |
| | @@ -13295,13 +13298,38 @@ |
| 13295 | 13298 | ** significantly more efficient than those alternatives when used with |
| 13296 | 13299 | ** "detail=column" tables. |
| 13297 | 13300 | ** |
| 13298 | 13301 | ** xPhraseNextColumn() |
| 13299 | 13302 | ** See xPhraseFirstColumn above. |
| 13303 | +** |
| 13304 | +** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) |
| 13305 | +** This is used to access token iToken of phrase iPhrase of the current |
| 13306 | +** query. Before returning, output parameter *ppToken is set to point |
| 13307 | +** to a buffer containing the requested token, and *pnToken to the |
| 13308 | +** size of this buffer in bytes. |
| 13309 | +** |
| 13310 | +** The output text is not a copy of the query text that specified the |
| 13311 | +** token. It is the output of the tokenizer module. For tokendata=1 |
| 13312 | +** tables, this includes any embedded 0x00 and trailing data. |
| 13313 | +** |
| 13314 | +** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) |
| 13315 | +** This is used to access token iToken of phrase hit iIdx within the |
| 13316 | +** current row. Output variable (*ppToken) is set to point to a buffer |
| 13317 | +** containing the matching document token, and (*pnToken) to the size |
| 13318 | +** of that buffer in bytes. This API is not available if the specified |
| 13319 | +** token matches a prefix query term. In that case both output variables |
| 13320 | +** are always set to 0. |
| 13321 | +** |
| 13322 | +** The output text is not a copy of the document text that was tokenized. |
| 13323 | +** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 13324 | +** includes any embedded 0x00 and trailing data. |
| 13325 | +** |
| 13326 | +** This API can be quite slow if used with an FTS5 table created with the |
| 13327 | +** "detail=none" or "detail=column" option. |
| 13300 | 13328 | */ |
| 13301 | 13329 | struct Fts5ExtensionApi { |
| 13302 | | - int iVersion; /* Currently always set to 2 */ |
| 13330 | + int iVersion; /* Currently always set to 3 */ |
| 13303 | 13331 | |
| 13304 | 13332 | void *(*xUserData)(Fts5Context*); |
| 13305 | 13333 | |
| 13306 | 13334 | int (*xColumnCount)(Fts5Context*); |
| 13307 | 13335 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -13332,10 +13360,17 @@ |
| 13332 | 13360 | int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 13333 | 13361 | void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); |
| 13334 | 13362 | |
| 13335 | 13363 | int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); |
| 13336 | 13364 | void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); |
| 13365 | + |
| 13366 | + /* Below this point are iVersion>=3 only */ |
| 13367 | + int (*xQueryToken)(Fts5Context*, |
| 13368 | + int iPhrase, int iToken, |
| 13369 | + const char **ppToken, int *pnToken |
| 13370 | + ); |
| 13371 | + int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); |
| 13337 | 13372 | }; |
| 13338 | 13373 | |
| 13339 | 13374 | /* |
| 13340 | 13375 | ** CUSTOM AUXILIARY FUNCTIONS |
| 13341 | 13376 | *************************************************************************/ |
| | @@ -16426,10 +16461,11 @@ |
| 16426 | 16461 | #define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ |
| 16427 | 16462 | #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ |
| 16428 | 16463 | #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ |
| 16429 | 16464 | #define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ |
| 16430 | 16465 | #define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ |
| 16466 | +#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ |
| 16431 | 16467 | |
| 16432 | 16468 | /* Error message codes for OP_Halt */ |
| 16433 | 16469 | #define P5_ConstraintNotNull 1 |
| 16434 | 16470 | #define P5_ConstraintUnique 2 |
| 16435 | 16471 | #define P5_ConstraintCheck 3 |
| | @@ -16648,17 +16684,19 @@ |
| 16648 | 16684 | #define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */ |
| 16649 | 16685 | #define OP_VRename 177 |
| 16650 | 16686 | #define OP_Pagecount 178 |
| 16651 | 16687 | #define OP_MaxPgcnt 179 |
| 16652 | 16688 | #define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */ |
| 16653 | | -#define OP_FilterAdd 181 /* synopsis: filter(P1) += key(P3@P4) */ |
| 16654 | | -#define OP_Trace 182 |
| 16655 | | -#define OP_CursorHint 183 |
| 16656 | | -#define OP_ReleaseReg 184 /* synopsis: release r[P1@P2] mask P3 */ |
| 16657 | | -#define OP_Noop 185 |
| 16658 | | -#define OP_Explain 186 |
| 16659 | | -#define OP_Abortable 187 |
| 16689 | +#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */ |
| 16690 | +#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */ |
| 16691 | +#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */ |
| 16692 | +#define OP_Trace 184 |
| 16693 | +#define OP_CursorHint 185 |
| 16694 | +#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */ |
| 16695 | +#define OP_Noop 187 |
| 16696 | +#define OP_Explain 188 |
| 16697 | +#define OP_Abortable 189 |
| 16660 | 16698 | |
| 16661 | 16699 | /* Properties such as "out2" or "jump" that are specified in |
| 16662 | 16700 | ** comments following the "case" for each opcode in the vdbe.c |
| 16663 | 16701 | ** are encoded into bitvectors as follows: |
| 16664 | 16702 | */ |
| | @@ -16690,12 +16728,12 @@ |
| 16690 | 16728 | /* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\ |
| 16691 | 16729 | /* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ |
| 16692 | 16730 | /* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ |
| 16693 | 16731 | /* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ |
| 16694 | 16732 | /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\ |
| 16695 | | -/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00,\ |
| 16696 | | -/* 184 */ 0x00, 0x00, 0x00, 0x00,} |
| 16733 | +/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\ |
| 16734 | +/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} |
| 16697 | 16735 | |
| 16698 | 16736 | /* The resolve3P2Values() routine is able to run faster if it knows |
| 16699 | 16737 | ** the value of the largest JUMP opcode. The smaller the maximum |
| 16700 | 16738 | ** JUMP opcode the better, so the mkopcodeh.tcl script that |
| 16701 | 16739 | ** generated this include file strives to group all JUMP opcodes |
| | @@ -17952,15 +17990,15 @@ |
| 17952 | 17990 | {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \ |
| 17953 | 17991 | SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } |
| 17954 | 17992 | #define MFUNCTION(zName, nArg, xPtr, xFunc) \ |
| 17955 | 17993 | {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \ |
| 17956 | 17994 | xPtr, 0, xFunc, 0, 0, 0, #zName, {0} } |
| 17957 | | -#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, iArg, xFunc) \ |
| 17995 | +#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \ |
| 17958 | 17996 | {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\ |
| 17959 | 17997 | SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\ |
| 17960 | 17998 | ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \ |
| 17961 | | - SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } |
| 17999 | + SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} } |
| 17962 | 18000 | #define INLINE_FUNC(zName, nArg, iArg, mFlags) \ |
| 17963 | 18001 | {nArg, SQLITE_FUNC_BUILTIN|\ |
| 17964 | 18002 | SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \ |
| 17965 | 18003 | SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} } |
| 17966 | 18004 | #define TEST_FUNC(zName, nArg, iArg, mFlags) \ |
| | @@ -18704,10 +18742,11 @@ |
| 18704 | 18742 | int iDistinct; /* Ephemeral table used to enforce DISTINCT */ |
| 18705 | 18743 | int iDistAddr; /* Address of OP_OpenEphemeral */ |
| 18706 | 18744 | int iOBTab; /* Ephemeral table to implement ORDER BY */ |
| 18707 | 18745 | u8 bOBPayload; /* iOBTab has payload columns separate from key */ |
| 18708 | 18746 | u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */ |
| 18747 | + u8 bUseSubtype; /* Transfer subtype info through sorter */ |
| 18709 | 18748 | } *aFunc; |
| 18710 | 18749 | int nFunc; /* Number of entries in aFunc[] */ |
| 18711 | 18750 | u32 selId; /* Select to which this AggInfo belongs */ |
| 18712 | 18751 | #ifdef SQLITE_DEBUG |
| 18713 | 18752 | Select *pSelect; /* SELECT statement that this AggInfo supports */ |
| | @@ -19237,10 +19276,11 @@ |
| 19237 | 19276 | } uNC; |
| 19238 | 19277 | NameContext *pNext; /* Next outer name context. NULL for outermost */ |
| 19239 | 19278 | int nRef; /* Number of names resolved by this context */ |
| 19240 | 19279 | int nNcErr; /* Number of errors encountered while resolving names */ |
| 19241 | 19280 | int ncFlags; /* Zero or more NC_* flags defined below */ |
| 19281 | + u32 nNestedSelect; /* Number of nested selects using this NC */ |
| 19242 | 19282 | Select *pWinSelect; /* SELECT statement for any window functions */ |
| 19243 | 19283 | }; |
| 19244 | 19284 | |
| 19245 | 19285 | /* |
| 19246 | 19286 | ** Allowed values for the NameContext, ncFlags field. |
| | @@ -19953,10 +19993,13 @@ |
| 19953 | 19993 | ** 2. Use sqlite3RCStrUnref() to free an RCStr string rather than |
| 19954 | 19994 | ** sqlite3_free() |
| 19955 | 19995 | ** |
| 19956 | 19996 | ** 3. Make a (read-only) copy of a read-only RCStr string using |
| 19957 | 19997 | ** sqlite3RCStrRef(). |
| 19998 | +** |
| 19999 | +** "String" is in the name, but an RCStr object can also be used to hold |
| 20000 | +** binary data. |
| 19958 | 20001 | */ |
| 19959 | 20002 | struct RCStr { |
| 19960 | 20003 | u64 nRCRef; /* Number of references */ |
| 19961 | 20004 | /* Total structure size should be a multiple of 8 bytes for alignment */ |
| 19962 | 20005 | }; |
| | @@ -20011,10 +20054,13 @@ |
| 20011 | 20054 | u8 bOpenUri; /* True to interpret filenames as URIs */ |
| 20012 | 20055 | u8 bUseCis; /* Use covering indices for full-scans */ |
| 20013 | 20056 | u8 bSmallMalloc; /* Avoid large memory allocations if true */ |
| 20014 | 20057 | u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */ |
| 20015 | 20058 | u8 bUseLongDouble; /* Make use of long double */ |
| 20059 | +#ifdef SQLITE_DEBUG |
| 20060 | + u8 bJsonSelfcheck; /* Double-check JSON parsing */ |
| 20061 | +#endif |
| 20016 | 20062 | int mxStrlen; /* Maximum string length */ |
| 20017 | 20063 | int neverCorrupt; /* Database is always well-formed */ |
| 20018 | 20064 | int szLookaside; /* Default lookaside buffer size */ |
| 20019 | 20065 | int nLookaside; /* Default lookaside buffer count */ |
| 20020 | 20066 | int nStmtSpill; /* Stmt-journal spill-to-disk threshold */ |
| | @@ -20637,19 +20683,21 @@ |
| 20637 | 20683 | SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*); |
| 20638 | 20684 | SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*); |
| 20639 | 20685 | SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*); |
| 20640 | 20686 | SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); |
| 20641 | 20687 | SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); |
| 20688 | +SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3*,void*); |
| 20642 | 20689 | SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*); |
| 20643 | 20690 | SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); |
| 20644 | 20691 | SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); |
| 20645 | 20692 | SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); |
| 20646 | 20693 | SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*); |
| 20647 | 20694 | SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int); |
| 20648 | 20695 | SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int); |
| 20649 | 20696 | SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*); |
| 20650 | 20697 | SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*); |
| 20698 | +SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3*,void*); |
| 20651 | 20699 | SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*); |
| 20652 | 20700 | SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*); |
| 20653 | 20701 | SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**); |
| 20654 | 20702 | SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**); |
| 20655 | 20703 | SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32); |
| | @@ -20736,10 +20784,11 @@ |
| 20736 | 20784 | SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask); |
| 20737 | 20785 | #endif |
| 20738 | 20786 | SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int); |
| 20739 | 20787 | SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int); |
| 20740 | 20788 | SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*); |
| 20789 | +SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3*, void*); |
| 20741 | 20790 | SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*); |
| 20742 | 20791 | #ifndef SQLITE_OMIT_AUTOINCREMENT |
| 20743 | 20792 | SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse); |
| 20744 | 20793 | SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse); |
| 20745 | 20794 | #else |
| | @@ -20772,10 +20821,11 @@ |
| 20772 | 20821 | SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int); |
| 20773 | 20822 | SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*); |
| 20774 | 20823 | SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, |
| 20775 | 20824 | Expr*,ExprList*,u32,Expr*); |
| 20776 | 20825 | SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); |
| 20826 | +SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); |
| 20777 | 20827 | SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); |
| 20778 | 20828 | SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); |
| 20779 | 20829 | SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); |
| 20780 | 20830 | #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) |
| 20781 | 20831 | SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); |
| | @@ -20998,10 +21048,11 @@ |
| 20998 | 21048 | #ifndef SQLITE_OMIT_UTF16 |
| 20999 | 21049 | SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); |
| 21000 | 21050 | #endif |
| 21001 | 21051 | SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); |
| 21002 | 21052 | SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**); |
| 21053 | +SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*); |
| 21003 | 21054 | SQLITE_PRIVATE LogEst sqlite3LogEst(u64); |
| 21004 | 21055 | SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst); |
| 21005 | 21056 | SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double); |
| 21006 | 21057 | SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst); |
| 21007 | 21058 | SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int); |
| | @@ -21344,10 +21395,11 @@ |
| 21344 | 21395 | #ifndef SQLITE_OMIT_CTE |
| 21345 | 21396 | SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8); |
| 21346 | 21397 | SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*); |
| 21347 | 21398 | SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*); |
| 21348 | 21399 | SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*); |
| 21400 | +SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3*,void*); |
| 21349 | 21401 | SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8); |
| 21350 | 21402 | #else |
| 21351 | 21403 | # define sqlite3CteNew(P,T,E,S) ((void*)0) |
| 21352 | 21404 | # define sqlite3CteDelete(D,C) |
| 21353 | 21405 | # define sqlite3CteWithAdd(P,W,C) ((void*)0) |
| | @@ -22721,10 +22773,13 @@ |
| 22721 | 22773 | SQLITE_USE_URI, /* bOpenUri */ |
| 22722 | 22774 | SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */ |
| 22723 | 22775 | 0, /* bSmallMalloc */ |
| 22724 | 22776 | 1, /* bExtraSchemaChecks */ |
| 22725 | 22777 | sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */ |
| 22778 | +#ifdef SQLITE_DEBUG |
| 22779 | + 0, /* bJsonSelfcheck */ |
| 22780 | +#endif |
| 22726 | 22781 | 0x7ffffffe, /* mxStrlen */ |
| 22727 | 22782 | 0, /* neverCorrupt */ |
| 22728 | 22783 | SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */ |
| 22729 | 22784 | SQLITE_STMTJRNL_SPILL, /* nStmtSpill */ |
| 22730 | 22785 | {0,0,0,0,0,0,0,0}, /* m */ |
| | @@ -25055,10 +25110,16 @@ |
| 25055 | 25110 | n = sqlite3_value_bytes(argv[i]); |
| 25056 | 25111 | if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1; |
| 25057 | 25112 | } |
| 25058 | 25113 | computeJD(p); |
| 25059 | 25114 | if( p->isError || !validJulianDay(p->iJD) ) return 1; |
| 25115 | + if( argc==1 && p->validYMD && p->D>28 ){ |
| 25116 | + /* Make sure a YYYY-MM-DD is normalized. |
| 25117 | + ** Example: 2023-02-31 -> 2023-03-03 */ |
| 25118 | + assert( p->validJD ); |
| 25119 | + p->validYMD = 0; |
| 25120 | + } |
| 25060 | 25121 | return 0; |
| 25061 | 25122 | } |
| 25062 | 25123 | |
| 25063 | 25124 | |
| 25064 | 25125 | /* |
| | @@ -32083,11 +32144,11 @@ |
| 32083 | 32144 | va_end(ap); |
| 32084 | 32145 | } |
| 32085 | 32146 | |
| 32086 | 32147 | |
| 32087 | 32148 | /***************************************************************************** |
| 32088 | | -** Reference counted string storage |
| 32149 | +** Reference counted string/blob storage |
| 32089 | 32150 | *****************************************************************************/ |
| 32090 | 32151 | |
| 32091 | 32152 | /* |
| 32092 | 32153 | ** Increase the reference count of the string by one. |
| 32093 | 32154 | ** |
| | @@ -32935,11 +32996,11 @@ |
| 32935 | 32996 | pX = pExpr->pLeft; |
| 32936 | 32997 | assert( ExprUseXList(pExpr) ); |
| 32937 | 32998 | assert( pExpr->x.pList->nExpr==2 ); |
| 32938 | 32999 | pY = pExpr->x.pList->a[0].pExpr; |
| 32939 | 33000 | pZ = pExpr->x.pList->a[1].pExpr; |
| 32940 | | - sqlite3TreeViewLine(pView, "BETWEEN"); |
| 33001 | + sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs); |
| 32941 | 33002 | sqlite3TreeViewExpr(pView, pX, 1); |
| 32942 | 33003 | sqlite3TreeViewExpr(pView, pY, 1); |
| 32943 | 33004 | sqlite3TreeViewExpr(pView, pZ, 0); |
| 32944 | 33005 | break; |
| 32945 | 33006 | } |
| | @@ -34070,11 +34131,42 @@ |
| 34070 | 34131 | || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } |
| 34071 | 34132 | } |
| 34072 | 34133 | return c; |
| 34073 | 34134 | } |
| 34074 | 34135 | |
| 34075 | | - |
| 34136 | +/* |
| 34137 | +** Read a single UTF8 character out of buffer z[], but reading no |
| 34138 | +** more than n characters from the buffer. z[] is not zero-terminated. |
| 34139 | +** |
| 34140 | +** Return the number of bytes used to construct the character. |
| 34141 | +** |
| 34142 | +** Invalid UTF8 might generate a strange result. No effort is made |
| 34143 | +** to detect invalid UTF8. |
| 34144 | +** |
| 34145 | +** At most 4 bytes will be read out of z[]. The return value will always |
| 34146 | +** be between 1 and 4. |
| 34147 | +*/ |
| 34148 | +SQLITE_PRIVATE int sqlite3Utf8ReadLimited( |
| 34149 | + const u8 *z, |
| 34150 | + int n, |
| 34151 | + u32 *piOut |
| 34152 | +){ |
| 34153 | + u32 c; |
| 34154 | + int i = 1; |
| 34155 | + assert( n>0 ); |
| 34156 | + c = z[0]; |
| 34157 | + if( c>=0xc0 ){ |
| 34158 | + c = sqlite3Utf8Trans1[c-0xc0]; |
| 34159 | + if( n>4 ) n = 4; |
| 34160 | + while( i<n && (z[i] & 0xc0)==0x80 ){ |
| 34161 | + c = (c<<6) + (0x3f & z[i]); |
| 34162 | + i++; |
| 34163 | + } |
| 34164 | + } |
| 34165 | + *piOut = c; |
| 34166 | + return i; |
| 34167 | +} |
| 34076 | 34168 | |
| 34077 | 34169 | |
| 34078 | 34170 | /* |
| 34079 | 34171 | ** If the TRANSLATE_TRACE macro is defined, the value of each Mem is |
| 34080 | 34172 | ** printed on stderr on the way into and out of sqlite3VdbeMemTranslate(). |
| | @@ -36839,17 +36931,19 @@ |
| 36839 | 36931 | /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), |
| 36840 | 36932 | /* 177 */ "VRename" OpHelp(""), |
| 36841 | 36933 | /* 178 */ "Pagecount" OpHelp(""), |
| 36842 | 36934 | /* 179 */ "MaxPgcnt" OpHelp(""), |
| 36843 | 36935 | /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), |
| 36844 | | - /* 181 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), |
| 36845 | | - /* 182 */ "Trace" OpHelp(""), |
| 36846 | | - /* 183 */ "CursorHint" OpHelp(""), |
| 36847 | | - /* 184 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), |
| 36848 | | - /* 185 */ "Noop" OpHelp(""), |
| 36849 | | - /* 186 */ "Explain" OpHelp(""), |
| 36850 | | - /* 187 */ "Abortable" OpHelp(""), |
| 36936 | + /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), |
| 36937 | + /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), |
| 36938 | + /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), |
| 36939 | + /* 184 */ "Trace" OpHelp(""), |
| 36940 | + /* 185 */ "CursorHint" OpHelp(""), |
| 36941 | + /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), |
| 36942 | + /* 187 */ "Noop" OpHelp(""), |
| 36943 | + /* 188 */ "Explain" OpHelp(""), |
| 36944 | + /* 189 */ "Abortable" OpHelp(""), |
| 36851 | 36945 | }; |
| 36852 | 36946 | return azName[i]; |
| 36853 | 36947 | } |
| 36854 | 36948 | #endif |
| 36855 | 36949 | |
| | @@ -41891,11 +41985,17 @@ |
| 41891 | 41985 | return SQLITE_OK; |
| 41892 | 41986 | } |
| 41893 | 41987 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 41894 | 41988 | case SQLITE_FCNTL_LOCK_TIMEOUT: { |
| 41895 | 41989 | int iOld = pFile->iBusyTimeout; |
| 41990 | +#if SQLITE_ENABLE_SETLK_TIMEOUT==1 |
| 41896 | 41991 | pFile->iBusyTimeout = *(int*)pArg; |
| 41992 | +#elif SQLITE_ENABLE_SETLK_TIMEOUT==2 |
| 41993 | + pFile->iBusyTimeout = !!(*(int*)pArg); |
| 41994 | +#else |
| 41995 | +# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2" |
| 41996 | +#endif |
| 41897 | 41997 | *(int*)pArg = iOld; |
| 41898 | 41998 | return SQLITE_OK; |
| 41899 | 41999 | } |
| 41900 | 42000 | #endif |
| 41901 | 42001 | #if SQLITE_MAX_MMAP_SIZE>0 |
| | @@ -42144,10 +42244,29 @@ |
| 42144 | 42244 | ** zFilename |
| 42145 | 42245 | ** |
| 42146 | 42246 | ** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and |
| 42147 | 42247 | ** unixMutexHeld() is true when reading or writing any other field |
| 42148 | 42248 | ** in this structure. |
| 42249 | +** |
| 42250 | +** aLock[SQLITE_SHM_NLOCK]: |
| 42251 | +** This array records the various locks held by clients on each of the |
| 42252 | +** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no |
| 42253 | +** locks are held by the process on this slot. If it is set to -1, then |
| 42254 | +** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[] |
| 42255 | +** value is set to a positive value, then it is the number of shared |
| 42256 | +** locks currently held on the slot. |
| 42257 | +** |
| 42258 | +** aMutex[SQLITE_SHM_NLOCK]: |
| 42259 | +** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex |
| 42260 | +** pShmMutex is used to protect the aLock[] array and the right to |
| 42261 | +** call fcntl() on unixShmNode.hShm to obtain or release locks. |
| 42262 | +** |
| 42263 | +** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array |
| 42264 | +** of mutexes - one for each locking slot. To read or write locking |
| 42265 | +** slot aLock[iSlot], the caller must hold the corresponding mutex |
| 42266 | +** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a |
| 42267 | +** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held. |
| 42149 | 42268 | */ |
| 42150 | 42269 | struct unixShmNode { |
| 42151 | 42270 | unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ |
| 42152 | 42271 | sqlite3_mutex *pShmMutex; /* Mutex to access this object */ |
| 42153 | 42272 | char *zFilename; /* Name of the mmapped file */ |
| | @@ -42157,14 +42276,15 @@ |
| 42157 | 42276 | u8 isReadonly; /* True if read-only */ |
| 42158 | 42277 | u8 isUnlocked; /* True if no DMS lock held */ |
| 42159 | 42278 | char **apRegion; /* Array of mapped shared-memory regions */ |
| 42160 | 42279 | int nRef; /* Number of unixShm objects pointing to this */ |
| 42161 | 42280 | unixShm *pFirst; /* All unixShm objects pointing to this */ |
| 42281 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42282 | + sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK]; |
| 42283 | +#endif |
| 42162 | 42284 | int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ |
| 42163 | 42285 | #ifdef SQLITE_DEBUG |
| 42164 | | - u8 exclMask; /* Mask of exclusive locks held */ |
| 42165 | | - u8 sharedMask; /* Mask of shared locks held */ |
| 42166 | 42286 | u8 nextShmId; /* Next available unixShm.id value */ |
| 42167 | 42287 | #endif |
| 42168 | 42288 | }; |
| 42169 | 42289 | |
| 42170 | 42290 | /* |
| | @@ -42243,20 +42363,33 @@ |
| 42243 | 42363 | ){ |
| 42244 | 42364 | unixShmNode *pShmNode; /* Apply locks to this open shared-memory segment */ |
| 42245 | 42365 | struct flock f; /* The posix advisory locking structure */ |
| 42246 | 42366 | int rc = SQLITE_OK; /* Result code form fcntl() */ |
| 42247 | 42367 | |
| 42248 | | - /* Access to the unixShmNode object is serialized by the caller */ |
| 42249 | 42368 | pShmNode = pFile->pInode->pShmNode; |
| 42250 | | - assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); |
| 42251 | | - assert( pShmNode->nRef>0 || unixMutexHeld() ); |
| 42369 | + |
| 42370 | + /* Assert that the correct mutex or mutexes are held. */ |
| 42371 | + if( pShmNode->nRef==0 ){ |
| 42372 | + assert( ofst==UNIX_SHM_DMS && n==1 && unixMutexHeld() ); |
| 42373 | + }else{ |
| 42374 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42375 | + int ii; |
| 42376 | + for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){ |
| 42377 | + assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) ); |
| 42378 | + } |
| 42379 | +#else |
| 42380 | + assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); |
| 42381 | + assert( pShmNode->nRef>0 ); |
| 42382 | +#endif |
| 42383 | + } |
| 42252 | 42384 | |
| 42253 | 42385 | /* Shared locks never span more than one byte */ |
| 42254 | 42386 | assert( n==1 || lockType!=F_RDLCK ); |
| 42255 | 42387 | |
| 42256 | 42388 | /* Locks are within range */ |
| 42257 | 42389 | assert( n>=1 && n<=SQLITE_SHM_NLOCK ); |
| 42390 | + assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) ); |
| 42258 | 42391 | |
| 42259 | 42392 | if( pShmNode->hShm>=0 ){ |
| 42260 | 42393 | int res; |
| 42261 | 42394 | /* Initialize the locking parameters */ |
| 42262 | 42395 | f.l_type = lockType; |
| | @@ -42263,50 +42396,39 @@ |
| 42263 | 42396 | f.l_whence = SEEK_SET; |
| 42264 | 42397 | f.l_start = ofst; |
| 42265 | 42398 | f.l_len = n; |
| 42266 | 42399 | res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); |
| 42267 | 42400 | if( res==-1 ){ |
| 42268 | | -#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42401 | +#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1 |
| 42269 | 42402 | rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY); |
| 42270 | 42403 | #else |
| 42271 | 42404 | rc = SQLITE_BUSY; |
| 42272 | 42405 | #endif |
| 42273 | 42406 | } |
| 42274 | 42407 | } |
| 42275 | 42408 | |
| 42276 | | - /* Update the global lock state and do debug tracing */ |
| 42277 | | -#ifdef SQLITE_DEBUG |
| 42278 | | - { u16 mask; |
| 42279 | | - OSTRACE(("SHM-LOCK ")); |
| 42280 | | - mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst); |
| 42281 | | - if( rc==SQLITE_OK ){ |
| 42282 | | - if( lockType==F_UNLCK ){ |
| 42283 | | - OSTRACE(("unlock %d ok", ofst)); |
| 42284 | | - pShmNode->exclMask &= ~mask; |
| 42285 | | - pShmNode->sharedMask &= ~mask; |
| 42286 | | - }else if( lockType==F_RDLCK ){ |
| 42287 | | - OSTRACE(("read-lock %d ok", ofst)); |
| 42288 | | - pShmNode->exclMask &= ~mask; |
| 42289 | | - pShmNode->sharedMask |= mask; |
| 42290 | | - }else{ |
| 42291 | | - assert( lockType==F_WRLCK ); |
| 42292 | | - OSTRACE(("write-lock %d ok", ofst)); |
| 42293 | | - pShmNode->exclMask |= mask; |
| 42294 | | - pShmNode->sharedMask &= ~mask; |
| 42295 | | - } |
| 42296 | | - }else{ |
| 42297 | | - if( lockType==F_UNLCK ){ |
| 42298 | | - OSTRACE(("unlock %d failed", ofst)); |
| 42299 | | - }else if( lockType==F_RDLCK ){ |
| 42300 | | - OSTRACE(("read-lock failed")); |
| 42301 | | - }else{ |
| 42302 | | - assert( lockType==F_WRLCK ); |
| 42303 | | - OSTRACE(("write-lock %d failed", ofst)); |
| 42304 | | - } |
| 42305 | | - } |
| 42306 | | - OSTRACE((" - afterwards %03x,%03x\n", |
| 42307 | | - pShmNode->sharedMask, pShmNode->exclMask)); |
| 42409 | + /* Do debug tracing */ |
| 42410 | +#ifdef SQLITE_DEBUG |
| 42411 | + OSTRACE(("SHM-LOCK ")); |
| 42412 | + if( rc==SQLITE_OK ){ |
| 42413 | + if( lockType==F_UNLCK ){ |
| 42414 | + OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1)); |
| 42415 | + }else if( lockType==F_RDLCK ){ |
| 42416 | + OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1)); |
| 42417 | + }else{ |
| 42418 | + assert( lockType==F_WRLCK ); |
| 42419 | + OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1)); |
| 42420 | + } |
| 42421 | + }else{ |
| 42422 | + if( lockType==F_UNLCK ){ |
| 42423 | + OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1)); |
| 42424 | + }else if( lockType==F_RDLCK ){ |
| 42425 | + OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1)); |
| 42426 | + }else{ |
| 42427 | + assert( lockType==F_WRLCK ); |
| 42428 | + OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1)); |
| 42429 | + } |
| 42308 | 42430 | } |
| 42309 | 42431 | #endif |
| 42310 | 42432 | |
| 42311 | 42433 | return rc; |
| 42312 | 42434 | } |
| | @@ -42340,10 +42462,15 @@ |
| 42340 | 42462 | if( p && ALWAYS(p->nRef==0) ){ |
| 42341 | 42463 | int nShmPerMap = unixShmRegionPerMap(); |
| 42342 | 42464 | int i; |
| 42343 | 42465 | assert( p->pInode==pFd->pInode ); |
| 42344 | 42466 | sqlite3_mutex_free(p->pShmMutex); |
| 42467 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42468 | + for(i=0; i<SQLITE_SHM_NLOCK; i++){ |
| 42469 | + sqlite3_mutex_free(p->aMutex[i]); |
| 42470 | + } |
| 42471 | +#endif |
| 42345 | 42472 | for(i=0; i<p->nRegion; i+=nShmPerMap){ |
| 42346 | 42473 | if( p->hShm>=0 ){ |
| 42347 | 42474 | osMunmap(p->apRegion[i], p->szRegion); |
| 42348 | 42475 | }else{ |
| 42349 | 42476 | sqlite3_free(p->apRegion[i]); |
| | @@ -42399,11 +42526,24 @@ |
| 42399 | 42526 | }else if( lock.l_type==F_UNLCK ){ |
| 42400 | 42527 | if( pShmNode->isReadonly ){ |
| 42401 | 42528 | pShmNode->isUnlocked = 1; |
| 42402 | 42529 | rc = SQLITE_READONLY_CANTINIT; |
| 42403 | 42530 | }else{ |
| 42531 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42532 | + /* Do not use a blocking lock here. If the lock cannot be obtained |
| 42533 | + ** immediately, it means some other connection is truncating the |
| 42534 | + ** *-shm file. And after it has done so, it will not release its |
| 42535 | + ** lock, but only downgrade it to a shared lock. So no point in |
| 42536 | + ** blocking here. The call below to obtain the shared DMS lock may |
| 42537 | + ** use a blocking lock. */ |
| 42538 | + int iSaveTimeout = pDbFd->iBusyTimeout; |
| 42539 | + pDbFd->iBusyTimeout = 0; |
| 42540 | +#endif |
| 42404 | 42541 | rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); |
| 42542 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42543 | + pDbFd->iBusyTimeout = iSaveTimeout; |
| 42544 | +#endif |
| 42405 | 42545 | /* The first connection to attach must truncate the -shm file. We |
| 42406 | 42546 | ** truncate to 3 bytes (an arbitrary small number, less than the |
| 42407 | 42547 | ** -shm header size) rather than 0 as a system debugging aid, to |
| 42408 | 42548 | ** help detect if a -shm file truncation is legitimate or is the work |
| 42409 | 42549 | ** or a rogue process. */ |
| | @@ -42520,10 +42660,22 @@ |
| 42520 | 42660 | pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| 42521 | 42661 | if( pShmNode->pShmMutex==0 ){ |
| 42522 | 42662 | rc = SQLITE_NOMEM_BKPT; |
| 42523 | 42663 | goto shm_open_err; |
| 42524 | 42664 | } |
| 42665 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42666 | + { |
| 42667 | + int ii; |
| 42668 | + for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){ |
| 42669 | + pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| 42670 | + if( pShmNode->aMutex[ii]==0 ){ |
| 42671 | + rc = SQLITE_NOMEM_BKPT; |
| 42672 | + goto shm_open_err; |
| 42673 | + } |
| 42674 | + } |
| 42675 | + } |
| 42676 | +#endif |
| 42525 | 42677 | } |
| 42526 | 42678 | |
| 42527 | 42679 | if( pInode->bProcessLock==0 ){ |
| 42528 | 42680 | if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ |
| 42529 | 42681 | pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW, |
| | @@ -42741,13 +42893,15 @@ |
| 42741 | 42893 | ** |
| 42742 | 42894 | ** assert( assertLockingArrayOk(pShmNode) ); |
| 42743 | 42895 | */ |
| 42744 | 42896 | #ifdef SQLITE_DEBUG |
| 42745 | 42897 | static int assertLockingArrayOk(unixShmNode *pShmNode){ |
| 42898 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42899 | + return 1; |
| 42900 | +#else |
| 42746 | 42901 | unixShm *pX; |
| 42747 | 42902 | int aLock[SQLITE_SHM_NLOCK]; |
| 42748 | | - assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); |
| 42749 | 42903 | |
| 42750 | 42904 | memset(aLock, 0, sizeof(aLock)); |
| 42751 | 42905 | for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
| 42752 | 42906 | int i; |
| 42753 | 42907 | for(i=0; i<SQLITE_SHM_NLOCK; i++){ |
| | @@ -42761,17 +42915,18 @@ |
| 42761 | 42915 | } |
| 42762 | 42916 | } |
| 42763 | 42917 | |
| 42764 | 42918 | assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) ); |
| 42765 | 42919 | return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); |
| 42920 | +#endif |
| 42766 | 42921 | } |
| 42767 | 42922 | #endif |
| 42768 | 42923 | |
| 42769 | 42924 | /* |
| 42770 | 42925 | ** Change the lock state for a shared-memory segment. |
| 42771 | 42926 | ** |
| 42772 | | -** Note that the relationship between SHAREd and EXCLUSIVE locks is a little |
| 42927 | +** Note that the relationship between SHARED and EXCLUSIVE locks is a little |
| 42773 | 42928 | ** different here than in posix. In xShmLock(), one can go from unlocked |
| 42774 | 42929 | ** to shared and back or from unlocked to exclusive and back. But one may |
| 42775 | 42930 | ** not go from shared to exclusive or from exclusive to shared. |
| 42776 | 42931 | */ |
| 42777 | 42932 | static int unixShmLock( |
| | @@ -42782,11 +42937,11 @@ |
| 42782 | 42937 | ){ |
| 42783 | 42938 | unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ |
| 42784 | 42939 | unixShm *p; /* The shared memory being locked */ |
| 42785 | 42940 | unixShmNode *pShmNode; /* The underlying file iNode */ |
| 42786 | 42941 | int rc = SQLITE_OK; /* Result code */ |
| 42787 | | - u16 mask; /* Mask of locks to take or release */ |
| 42942 | + u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */ |
| 42788 | 42943 | int *aLock; |
| 42789 | 42944 | |
| 42790 | 42945 | p = pDbFd->pShm; |
| 42791 | 42946 | if( p==0 ) return SQLITE_IOERR_SHMLOCK; |
| 42792 | 42947 | pShmNode = p->pShmNode; |
| | @@ -42817,92 +42972,154 @@ |
| 42817 | 42972 | ** held. |
| 42818 | 42973 | ** |
| 42819 | 42974 | ** It is not permitted to block on the RECOVER lock. |
| 42820 | 42975 | */ |
| 42821 | 42976 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 42822 | | - assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( |
| 42823 | | - (ofst!=2) /* not RECOVER */ |
| 42824 | | - && (ofst!=1 || (p->exclMask|p->sharedMask)==0) |
| 42825 | | - && (ofst!=0 || (p->exclMask|p->sharedMask)<3) |
| 42826 | | - && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst)) |
| 42827 | | - )); |
| 42828 | | -#endif |
| 42829 | | - |
| 42830 | | - mask = (1<<(ofst+n)) - (1<<ofst); |
| 42831 | | - assert( n>1 || mask==(1<<ofst) ); |
| 42832 | | - sqlite3_mutex_enter(pShmNode->pShmMutex); |
| 42833 | | - assert( assertLockingArrayOk(pShmNode) ); |
| 42834 | | - if( flags & SQLITE_SHM_UNLOCK ){ |
| 42835 | | - if( (p->exclMask|p->sharedMask) & mask ){ |
| 42836 | | - int ii; |
| 42837 | | - int bUnlock = 1; |
| 42838 | | - |
| 42839 | | - for(ii=ofst; ii<ofst+n; ii++){ |
| 42840 | | - if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){ |
| 42841 | | - bUnlock = 0; |
| 42842 | | - } |
| 42843 | | - } |
| 42844 | | - |
| 42845 | | - if( bUnlock ){ |
| 42846 | | - rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); |
| 42847 | | - if( rc==SQLITE_OK ){ |
| 42848 | | - memset(&aLock[ofst], 0, sizeof(int)*n); |
| 42849 | | - } |
| 42850 | | - }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){ |
| 42851 | | - assert( n==1 && aLock[ofst]>1 ); |
| 42852 | | - aLock[ofst]--; |
| 42853 | | - } |
| 42854 | | - |
| 42855 | | - /* Undo the local locks */ |
| 42856 | | - if( rc==SQLITE_OK ){ |
| 42857 | | - p->exclMask &= ~mask; |
| 42858 | | - p->sharedMask &= ~mask; |
| 42859 | | - } |
| 42860 | | - } |
| 42861 | | - }else if( flags & SQLITE_SHM_SHARED ){ |
| 42862 | | - assert( n==1 ); |
| 42863 | | - assert( (p->exclMask & (1<<ofst))==0 ); |
| 42864 | | - if( (p->sharedMask & mask)==0 ){ |
| 42865 | | - if( aLock[ofst]<0 ){ |
| 42866 | | - rc = SQLITE_BUSY; |
| 42867 | | - }else if( aLock[ofst]==0 ){ |
| 42868 | | - rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); |
| 42869 | | - } |
| 42870 | | - |
| 42871 | | - /* Get the local shared locks */ |
| 42872 | | - if( rc==SQLITE_OK ){ |
| 42873 | | - p->sharedMask |= mask; |
| 42874 | | - aLock[ofst]++; |
| 42875 | | - } |
| 42876 | | - } |
| 42877 | | - }else{ |
| 42878 | | - /* Make sure no sibling connections hold locks that will block this |
| 42879 | | - ** lock. If any do, return SQLITE_BUSY right away. */ |
| 42880 | | - int ii; |
| 42881 | | - for(ii=ofst; ii<ofst+n; ii++){ |
| 42882 | | - assert( (p->sharedMask & mask)==0 ); |
| 42883 | | - if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){ |
| 42884 | | - rc = SQLITE_BUSY; |
| 42885 | | - break; |
| 42886 | | - } |
| 42887 | | - } |
| 42888 | | - |
| 42889 | | - /* Get the exclusive locks at the system level. Then if successful |
| 42890 | | - ** also update the in-memory values. */ |
| 42891 | | - if( rc==SQLITE_OK ){ |
| 42892 | | - rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); |
| 42893 | | - if( rc==SQLITE_OK ){ |
| 42894 | | - assert( (p->sharedMask & mask)==0 ); |
| 42895 | | - p->exclMask |= mask; |
| 42896 | | - for(ii=ofst; ii<ofst+n; ii++){ |
| 42897 | | - aLock[ii] = -1; |
| 42898 | | - } |
| 42899 | | - } |
| 42900 | | - } |
| 42901 | | - } |
| 42902 | | - assert( assertLockingArrayOk(pShmNode) ); |
| 42903 | | - sqlite3_mutex_leave(pShmNode->pShmMutex); |
| 42977 | + { |
| 42978 | + u16 lockMask = (p->exclMask|p->sharedMask); |
| 42979 | + assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || ( |
| 42980 | + (ofst!=2) /* not RECOVER */ |
| 42981 | + && (ofst!=1 || lockMask==0 || lockMask==2) |
| 42982 | + && (ofst!=0 || lockMask<3) |
| 42983 | + && (ofst<3 || lockMask<(1<<ofst)) |
| 42984 | + )); |
| 42985 | + } |
| 42986 | +#endif |
| 42987 | + |
| 42988 | + /* Check if there is any work to do. There are three cases: |
| 42989 | + ** |
| 42990 | + ** a) An unlock operation where there are locks to unlock, |
| 42991 | + ** b) An shared lock where the requested lock is not already held |
| 42992 | + ** c) An exclusive lock where the requested lock is not already held |
| 42993 | + ** |
| 42994 | + ** The SQLite core never requests an exclusive lock that it already holds. |
| 42995 | + ** This is assert()ed below. |
| 42996 | + */ |
| 42997 | + assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK) |
| 42998 | + || 0==(p->exclMask & mask) |
| 42999 | + ); |
| 43000 | + if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask)) |
| 43001 | + || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask)) |
| 43002 | + || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)) |
| 43003 | + ){ |
| 43004 | + |
| 43005 | + /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if |
| 43006 | + ** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any |
| 43007 | + ** other thread is holding this mutex, then it is either holding or about |
| 43008 | + ** to hold a lock exclusive to the one being requested, and we may |
| 43009 | + ** therefore return SQLITE_BUSY to the caller. |
| 43010 | + ** |
| 43011 | + ** Doing this prevents some deadlock scenarios. For example, thread 1 may |
| 43012 | + ** be a checkpointer blocked waiting on the WRITER lock. And thread 2 |
| 43013 | + ** may be a normal SQL client upgrading to a write transaction. In this |
| 43014 | + ** case thread 2 does a non-blocking request for the WRITER lock. But - |
| 43015 | + ** if it were to use sqlite3_mutex_enter() then it would effectively |
| 43016 | + ** become a (doomed) blocking request, as thread 2 would block until thread |
| 43017 | + ** 1 obtained WRITER and released the mutex. Since thread 2 already holds |
| 43018 | + ** a lock on a read-locking slot at this point, this breaks the |
| 43019 | + ** anti-deadlock rules (see above). */ |
| 43020 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 43021 | + int iMutex; |
| 43022 | + for(iMutex=ofst; iMutex<ofst+n; iMutex++){ |
| 43023 | + if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){ |
| 43024 | + rc = sqlite3_mutex_try(pShmNode->aMutex[iMutex]); |
| 43025 | + if( rc!=SQLITE_OK ) break; |
| 43026 | + }else{ |
| 43027 | + sqlite3_mutex_enter(pShmNode->aMutex[iMutex]); |
| 43028 | + } |
| 43029 | + } |
| 43030 | +#else |
| 43031 | + sqlite3_mutex_enter(pShmNode->pShmMutex); |
| 43032 | +#endif |
| 43033 | + |
| 43034 | + if( rc==SQLITE_OK ){ |
| 43035 | + if( flags & SQLITE_SHM_UNLOCK ){ |
| 43036 | + /* Case (a) - unlock. */ |
| 43037 | + int bUnlock = 1; |
| 43038 | + assert( (p->exclMask & p->sharedMask)==0 ); |
| 43039 | + assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask ); |
| 43040 | + assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask ); |
| 43041 | + |
| 43042 | + /* If this is a SHARED lock being unlocked, it is possible that other |
| 43043 | + ** clients within this process are holding the same SHARED lock. In |
| 43044 | + ** this case, set bUnlock to 0 so that the posix lock is not removed |
| 43045 | + ** from the file-descriptor below. */ |
| 43046 | + if( flags & SQLITE_SHM_SHARED ){ |
| 43047 | + assert( n==1 ); |
| 43048 | + assert( aLock[ofst]>=1 ); |
| 43049 | + if( aLock[ofst]>1 ){ |
| 43050 | + bUnlock = 0; |
| 43051 | + aLock[ofst]--; |
| 43052 | + p->sharedMask &= ~mask; |
| 43053 | + } |
| 43054 | + } |
| 43055 | + |
| 43056 | + if( bUnlock ){ |
| 43057 | + rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); |
| 43058 | + if( rc==SQLITE_OK ){ |
| 43059 | + memset(&aLock[ofst], 0, sizeof(int)*n); |
| 43060 | + p->sharedMask &= ~mask; |
| 43061 | + p->exclMask &= ~mask; |
| 43062 | + } |
| 43063 | + } |
| 43064 | + }else if( flags & SQLITE_SHM_SHARED ){ |
| 43065 | + /* Case (b) - a shared lock. */ |
| 43066 | + |
| 43067 | + if( aLock[ofst]<0 ){ |
| 43068 | + /* An exclusive lock is held by some other connection. BUSY. */ |
| 43069 | + rc = SQLITE_BUSY; |
| 43070 | + }else if( aLock[ofst]==0 ){ |
| 43071 | + rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); |
| 43072 | + } |
| 43073 | + |
| 43074 | + /* Get the local shared locks */ |
| 43075 | + if( rc==SQLITE_OK ){ |
| 43076 | + p->sharedMask |= mask; |
| 43077 | + aLock[ofst]++; |
| 43078 | + } |
| 43079 | + }else{ |
| 43080 | + /* Case (c) - an exclusive lock. */ |
| 43081 | + int ii; |
| 43082 | + |
| 43083 | + assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ); |
| 43084 | + assert( (p->sharedMask & mask)==0 ); |
| 43085 | + assert( (p->exclMask & mask)==0 ); |
| 43086 | + |
| 43087 | + /* Make sure no sibling connections hold locks that will block this |
| 43088 | + ** lock. If any do, return SQLITE_BUSY right away. */ |
| 43089 | + for(ii=ofst; ii<ofst+n; ii++){ |
| 43090 | + if( aLock[ii] ){ |
| 43091 | + rc = SQLITE_BUSY; |
| 43092 | + break; |
| 43093 | + } |
| 43094 | + } |
| 43095 | + |
| 43096 | + /* Get the exclusive locks at the system level. Then if successful |
| 43097 | + ** also update the in-memory values. */ |
| 43098 | + if( rc==SQLITE_OK ){ |
| 43099 | + rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n); |
| 43100 | + if( rc==SQLITE_OK ){ |
| 43101 | + p->exclMask |= mask; |
| 43102 | + for(ii=ofst; ii<ofst+n; ii++){ |
| 43103 | + aLock[ii] = -1; |
| 43104 | + } |
| 43105 | + } |
| 43106 | + } |
| 43107 | + } |
| 43108 | + assert( assertLockingArrayOk(pShmNode) ); |
| 43109 | + } |
| 43110 | + |
| 43111 | + /* Drop the mutexes acquired above. */ |
| 43112 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 43113 | + for(iMutex--; iMutex>=ofst; iMutex--){ |
| 43114 | + sqlite3_mutex_leave(pShmNode->aMutex[iMutex]); |
| 43115 | + } |
| 43116 | +#else |
| 43117 | + sqlite3_mutex_leave(pShmNode->pShmMutex); |
| 43118 | +#endif |
| 43119 | + } |
| 43120 | + |
| 42904 | 43121 | OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", |
| 42905 | 43122 | p->id, osGetpid(0), p->sharedMask, p->exclMask)); |
| 42906 | 43123 | return rc; |
| 42907 | 43124 | } |
| 42908 | 43125 | |
| | @@ -66236,10 +66453,23 @@ |
| 66236 | 66453 | *pp = p; |
| 66237 | 66454 | return rc; |
| 66238 | 66455 | } |
| 66239 | 66456 | |
| 66240 | 66457 | #ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 66458 | + |
| 66459 | + |
| 66460 | +/* |
| 66461 | +** Attempt to enable blocking locks that block for nMs ms. Return 1 if |
| 66462 | +** blocking locks are successfully enabled, or 0 otherwise. |
| 66463 | +*/ |
| 66464 | +static int walEnableBlockingMs(Wal *pWal, int nMs){ |
| 66465 | + int rc = sqlite3OsFileControl( |
| 66466 | + pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs |
| 66467 | + ); |
| 66468 | + return (rc==SQLITE_OK); |
| 66469 | +} |
| 66470 | + |
| 66241 | 66471 | /* |
| 66242 | 66472 | ** Attempt to enable blocking locks. Blocking locks are enabled only if (a) |
| 66243 | 66473 | ** they are supported by the VFS, and (b) the database handle is configured |
| 66244 | 66474 | ** with a busy-timeout. Return 1 if blocking locks are successfully enabled, |
| 66245 | 66475 | ** or 0 otherwise. |
| | @@ -66247,15 +66477,11 @@ |
| 66247 | 66477 | static int walEnableBlocking(Wal *pWal){ |
| 66248 | 66478 | int res = 0; |
| 66249 | 66479 | if( pWal->db ){ |
| 66250 | 66480 | int tmout = pWal->db->busyTimeout; |
| 66251 | 66481 | if( tmout ){ |
| 66252 | | - int rc; |
| 66253 | | - rc = sqlite3OsFileControl( |
| 66254 | | - pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout |
| 66255 | | - ); |
| 66256 | | - res = (rc==SQLITE_OK); |
| 66482 | + res = walEnableBlockingMs(pWal, tmout); |
| 66257 | 66483 | } |
| 66258 | 66484 | } |
| 66259 | 66485 | return res; |
| 66260 | 66486 | } |
| 66261 | 66487 | |
| | @@ -66300,24 +66526,14 @@ |
| 66300 | 66526 | */ |
| 66301 | 66527 | SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){ |
| 66302 | 66528 | pWal->db = db; |
| 66303 | 66529 | } |
| 66304 | 66530 | |
| 66305 | | -/* |
| 66306 | | -** Take an exclusive WRITE lock. Blocking if so configured. |
| 66307 | | -*/ |
| 66308 | | -static int walLockWriter(Wal *pWal){ |
| 66309 | | - int rc; |
| 66310 | | - walEnableBlocking(pWal); |
| 66311 | | - rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1); |
| 66312 | | - walDisableBlocking(pWal); |
| 66313 | | - return rc; |
| 66314 | | -} |
| 66315 | 66531 | #else |
| 66316 | 66532 | # define walEnableBlocking(x) 0 |
| 66317 | 66533 | # define walDisableBlocking(x) |
| 66318 | | -# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1) |
| 66534 | +# define walEnableBlockingMs(pWal, ms) 0 |
| 66319 | 66535 | # define sqlite3WalDb(pWal, db) |
| 66320 | 66536 | #endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */ |
| 66321 | 66537 | |
| 66322 | 66538 | |
| 66323 | 66539 | /* |
| | @@ -66914,19 +67130,22 @@ |
| 66914 | 67130 | walUnlockShared(pWal, WAL_WRITE_LOCK); |
| 66915 | 67131 | rc = SQLITE_READONLY_RECOVERY; |
| 66916 | 67132 | } |
| 66917 | 67133 | }else{ |
| 66918 | 67134 | int bWriteLock = pWal->writeLock; |
| 66919 | | - if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ |
| 67135 | + if( bWriteLock |
| 67136 | + || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) |
| 67137 | + ){ |
| 66920 | 67138 | pWal->writeLock = 1; |
| 66921 | 67139 | if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ |
| 66922 | 67140 | badHdr = walIndexTryHdr(pWal, pChanged); |
| 66923 | 67141 | if( badHdr ){ |
| 66924 | 67142 | /* If the wal-index header is still malformed even while holding |
| 66925 | 67143 | ** a WRITE lock, it can only mean that the header is corrupted and |
| 66926 | 67144 | ** needs to be reconstructed. So run recovery to do exactly that. |
| 66927 | | - */ |
| 67145 | + ** Disable blocking locks first. */ |
| 67146 | + walDisableBlocking(pWal); |
| 66928 | 67147 | rc = walIndexRecover(pWal); |
| 66929 | 67148 | *pChanged = 1; |
| 66930 | 67149 | } |
| 66931 | 67150 | } |
| 66932 | 67151 | if( bWriteLock==0 ){ |
| | @@ -67189,10 +67408,13 @@ |
| 67189 | 67408 | u32 mxReadMark; /* Largest aReadMark[] value */ |
| 67190 | 67409 | int mxI; /* Index of largest aReadMark[] value */ |
| 67191 | 67410 | int i; /* Loop counter */ |
| 67192 | 67411 | int rc = SQLITE_OK; /* Return code */ |
| 67193 | 67412 | u32 mxFrame; /* Wal frame to lock to */ |
| 67413 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 67414 | + int nBlockTmout = 0; |
| 67415 | +#endif |
| 67194 | 67416 | |
| 67195 | 67417 | assert( pWal->readLock<0 ); /* Not currently locked */ |
| 67196 | 67418 | |
| 67197 | 67419 | /* useWal may only be set for read/write connections */ |
| 67198 | 67420 | assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 ); |
| | @@ -67219,18 +67441,35 @@ |
| 67219 | 67441 | if( cnt>100 ){ |
| 67220 | 67442 | VVA_ONLY( pWal->lockError = 1; ) |
| 67221 | 67443 | return SQLITE_PROTOCOL; |
| 67222 | 67444 | } |
| 67223 | 67445 | if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39; |
| 67446 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 67447 | + /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor |
| 67448 | + ** to block for locks for approximately nDelay us. This affects three |
| 67449 | + ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if |
| 67450 | + ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the |
| 67451 | + ** first attempted read fails, and (c) the shared lock taken on the DMS |
| 67452 | + ** slot in os_unix.c. All three of these locks are attempted from within |
| 67453 | + ** the call to walIndexReadHdr() below. */ |
| 67454 | + nBlockTmout = (nDelay+998) / 1000; |
| 67455 | + if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){ |
| 67456 | + nDelay = 1; |
| 67457 | + } |
| 67458 | +#endif |
| 67224 | 67459 | sqlite3OsSleep(pWal->pVfs, nDelay); |
| 67225 | 67460 | } |
| 67226 | 67461 | |
| 67227 | 67462 | if( !useWal ){ |
| 67228 | 67463 | assert( rc==SQLITE_OK ); |
| 67229 | 67464 | if( pWal->bShmUnreliable==0 ){ |
| 67230 | 67465 | rc = walIndexReadHdr(pWal, pChanged); |
| 67231 | 67466 | } |
| 67467 | +#ifdef SQLITE_ENABLE_SETLK_TIMEOUT |
| 67468 | + walDisableBlocking(pWal); |
| 67469 | + if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; |
| 67470 | +#endif |
| 67232 | 67471 | if( rc==SQLITE_BUSY ){ |
| 67233 | 67472 | /* If there is not a recovery running in another thread or process |
| 67234 | 67473 | ** then convert BUSY errors to WAL_RETRY. If recovery is known to |
| 67235 | 67474 | ** be running, convert BUSY to BUSY_RECOVERY. There is a race here |
| 67236 | 67475 | ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY |
| | @@ -67341,13 +67580,16 @@ |
| 67341 | 67580 | if( mxI==0 ){ |
| 67342 | 67581 | assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 ); |
| 67343 | 67582 | return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT; |
| 67344 | 67583 | } |
| 67345 | 67584 | |
| 67585 | + (void)walEnableBlockingMs(pWal, nBlockTmout); |
| 67346 | 67586 | rc = walLockShared(pWal, WAL_READ_LOCK(mxI)); |
| 67587 | + walDisableBlocking(pWal); |
| 67347 | 67588 | if( rc ){ |
| 67348 | | - return rc==SQLITE_BUSY ? WAL_RETRY : rc; |
| 67589 | + assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT ); |
| 67590 | + return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc; |
| 67349 | 67591 | } |
| 67350 | 67592 | /* Now that the read-lock has been obtained, check that neither the |
| 67351 | 67593 | ** value in the aReadMark[] array or the contents of the wal-index |
| 67352 | 67594 | ** header have changed. |
| 67353 | 67595 | ** |
| | @@ -68436,14 +68678,13 @@ |
| 68436 | 68678 | assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 ); |
| 68437 | 68679 | |
| 68438 | 68680 | if( pWal->readOnly ) return SQLITE_READONLY; |
| 68439 | 68681 | WALTRACE(("WAL%p: checkpoint begins\n", pWal)); |
| 68440 | 68682 | |
| 68441 | | - /* Enable blocking locks, if possible. If blocking locks are successfully |
| 68442 | | - ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */ |
| 68683 | + /* Enable blocking locks, if possible. */ |
| 68443 | 68684 | sqlite3WalDb(pWal, db); |
| 68444 | | - (void)walEnableBlocking(pWal); |
| 68685 | + if( xBusy2 ) (void)walEnableBlocking(pWal); |
| 68445 | 68686 | |
| 68446 | 68687 | /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive |
| 68447 | 68688 | ** "checkpoint" lock on the database file. |
| 68448 | 68689 | ** EVIDENCE-OF: R-10421-19736 If any other process is running a |
| 68449 | 68690 | ** checkpoint operation at the same time, the lock cannot be obtained and |
| | @@ -68480,13 +68721,18 @@ |
| 68480 | 68721 | |
| 68481 | 68722 | |
| 68482 | 68723 | /* Read the wal-index header. */ |
| 68483 | 68724 | SEH_TRY { |
| 68484 | 68725 | if( rc==SQLITE_OK ){ |
| 68726 | + /* For a passive checkpoint, do not re-enable blocking locks after |
| 68727 | + ** reading the wal-index header. A passive checkpoint should not block |
| 68728 | + ** or invoke the busy handler. The only lock such a checkpoint may |
| 68729 | + ** attempt to obtain is a lock on a read-slot, and it should give up |
| 68730 | + ** immediately and do a partial checkpoint if it cannot obtain it. */ |
| 68485 | 68731 | walDisableBlocking(pWal); |
| 68486 | 68732 | rc = walIndexReadHdr(pWal, &isChanged); |
| 68487 | | - (void)walEnableBlocking(pWal); |
| 68733 | + if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal); |
| 68488 | 68734 | if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ |
| 68489 | 68735 | sqlite3OsUnfetch(pWal->pDbFd, 0, 0); |
| 68490 | 68736 | } |
| 68491 | 68737 | } |
| 68492 | 68738 | |
| | @@ -68819,11 +69065,11 @@ |
| 68819 | 69065 | ** 20 1 Bytes of unused space at the end of each page |
| 68820 | 69066 | ** 21 1 Max embedded payload fraction (must be 64) |
| 68821 | 69067 | ** 22 1 Min embedded payload fraction (must be 32) |
| 68822 | 69068 | ** 23 1 Min leaf payload fraction (must be 32) |
| 68823 | 69069 | ** 24 4 File change counter |
| 68824 | | -** 28 4 Reserved for future use |
| 69070 | +** 28 4 The size of the database in pages |
| 68825 | 69071 | ** 32 4 First freelist page |
| 68826 | 69072 | ** 36 4 Number of freelist pages in the file |
| 68827 | 69073 | ** 40 60 15 4-byte meta values passed to higher layers |
| 68828 | 69074 | ** |
| 68829 | 69075 | ** 40 4 Schema cookie |
| | @@ -85370,10 +85616,14 @@ |
| 85370 | 85616 | } |
| 85371 | 85617 | case P4_VTAB : { |
| 85372 | 85618 | if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); |
| 85373 | 85619 | break; |
| 85374 | 85620 | } |
| 85621 | + case P4_TABLEREF: { |
| 85622 | + if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4); |
| 85623 | + break; |
| 85624 | + } |
| 85375 | 85625 | } |
| 85376 | 85626 | } |
| 85377 | 85627 | |
| 85378 | 85628 | /* |
| 85379 | 85629 | ** Free the space allocated for aOp and any p4 values allocated for the |
| | @@ -85497,11 +85747,11 @@ |
| 85497 | 85747 | Op *pOp, |
| 85498 | 85748 | const char *zP4, |
| 85499 | 85749 | int n |
| 85500 | 85750 | ){ |
| 85501 | 85751 | if( pOp->p4type ){ |
| 85502 | | - freeP4(p->db, pOp->p4type, pOp->p4.p); |
| 85752 | + assert( pOp->p4type > P4_FREE_IF_LE ); |
| 85503 | 85753 | pOp->p4type = 0; |
| 85504 | 85754 | pOp->p4.p = 0; |
| 85505 | 85755 | } |
| 85506 | 85756 | if( n<0 ){ |
| 85507 | 85757 | sqlite3VdbeChangeP4(p, (int)(pOp - p->aOp), zP4, n); |
| | @@ -89620,11 +89870,19 @@ |
| 89620 | 89870 | SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ |
| 89621 | 89871 | int i; |
| 89622 | 89872 | int rc = SQLITE_OK; |
| 89623 | 89873 | Vdbe *p = (Vdbe*)pStmt; |
| 89624 | 89874 | #if SQLITE_THREADSAFE |
| 89625 | | - sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; |
| 89875 | + sqlite3_mutex *mutex; |
| 89876 | +#endif |
| 89877 | +#ifdef SQLITE_ENABLE_API_ARMOR |
| 89878 | + if( pStmt==0 ){ |
| 89879 | + return SQLITE_MISUSE_BKPT; |
| 89880 | + } |
| 89881 | +#endif |
| 89882 | +#if SQLITE_THREADSAFE |
| 89883 | + mutex = p->db->mutex; |
| 89626 | 89884 | #endif |
| 89627 | 89885 | sqlite3_mutex_enter(mutex); |
| 89628 | 89886 | for(i=0; i<p->nVar; i++){ |
| 89629 | 89887 | sqlite3VdbeMemRelease(&p->aVar[i]); |
| 89630 | 89888 | p->aVar[i].flags = MEM_Null; |
| | @@ -90410,13 +90668,12 @@ |
| 90410 | 90668 | ** pointer to it. |
| 90411 | 90669 | */ |
| 90412 | 90670 | SQLITE_API void *sqlite3_user_data(sqlite3_context *p){ |
| 90413 | 90671 | #ifdef SQLITE_ENABLE_API_ARMOR |
| 90414 | 90672 | if( p==0 ) return 0; |
| 90415 | | -#else |
| 90673 | +#endif |
| 90416 | 90674 | assert( p && p->pFunc ); |
| 90417 | | -#endif |
| 90418 | 90675 | return p->pFunc->pUserData; |
| 90419 | 90676 | } |
| 90420 | 90677 | |
| 90421 | 90678 | /* |
| 90422 | 90679 | ** Extract the user data from a sqlite3_context structure and return a |
| | @@ -94231,11 +94488,11 @@ |
| 94231 | 94488 | */ |
| 94232 | 94489 | case OP_AddImm: { /* in1 */ |
| 94233 | 94490 | pIn1 = &aMem[pOp->p1]; |
| 94234 | 94491 | memAboutToChange(p, pIn1); |
| 94235 | 94492 | sqlite3VdbeMemIntegerify(pIn1); |
| 94236 | | - pIn1->u.i += pOp->p2; |
| 94493 | + *(u64*)&pIn1->u.i += (u64)pOp->p2; |
| 94237 | 94494 | break; |
| 94238 | 94495 | } |
| 94239 | 94496 | |
| 94240 | 94497 | /* Opcode: MustBeInt P1 P2 * * * |
| 94241 | 94498 | ** |
| | @@ -100377,28 +100634,27 @@ |
| 100377 | 100634 | const sqlite3_module *pModule; |
| 100378 | 100635 | char *zErr = 0; |
| 100379 | 100636 | |
| 100380 | 100637 | pOut = &aMem[pOp->p2]; |
| 100381 | 100638 | sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */ |
| 100382 | | - assert( pOp->p4type==P4_TABLE ); |
| 100639 | + assert( pOp->p4type==P4_TABLEREF ); |
| 100383 | 100640 | pTab = pOp->p4.pTab; |
| 100384 | 100641 | assert( pTab!=0 ); |
| 100642 | + assert( pTab->nTabRef>0 ); |
| 100385 | 100643 | assert( IsVirtual(pTab) ); |
| 100386 | 100644 | if( pTab->u.vtab.p==0 ) break; |
| 100387 | 100645 | pVtab = pTab->u.vtab.p->pVtab; |
| 100388 | 100646 | assert( pVtab!=0 ); |
| 100389 | 100647 | pModule = pVtab->pModule; |
| 100390 | 100648 | assert( pModule!=0 ); |
| 100391 | 100649 | assert( pModule->iVersion>=4 ); |
| 100392 | 100650 | assert( pModule->xIntegrity!=0 ); |
| 100393 | | - pTab->nTabRef++; |
| 100394 | 100651 | sqlite3VtabLock(pTab->u.vtab.p); |
| 100395 | 100652 | assert( pOp->p1>=0 && pOp->p1<db->nDb ); |
| 100396 | 100653 | rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName, |
| 100397 | 100654 | pOp->p3, &zErr); |
| 100398 | 100655 | sqlite3VtabUnlock(pTab->u.vtab.p); |
| 100399 | | - sqlite3DeleteTable(db, pTab); |
| 100400 | 100656 | if( rc ){ |
| 100401 | 100657 | sqlite3_free(zErr); |
| 100402 | 100658 | goto abort_due_to_error; |
| 100403 | 100659 | } |
| 100404 | 100660 | if( zErr ){ |
| | @@ -100519,10 +100775,11 @@ |
| 100519 | 100775 | case OP_VColumn: { /* ncycle */ |
| 100520 | 100776 | sqlite3_vtab *pVtab; |
| 100521 | 100777 | const sqlite3_module *pModule; |
| 100522 | 100778 | Mem *pDest; |
| 100523 | 100779 | sqlite3_context sContext; |
| 100780 | + FuncDef nullFunc; |
| 100524 | 100781 | |
| 100525 | 100782 | VdbeCursor *pCur = p->apCsr[pOp->p1]; |
| 100526 | 100783 | assert( pCur!=0 ); |
| 100527 | 100784 | assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); |
| 100528 | 100785 | pDest = &aMem[pOp->p3]; |
| | @@ -100536,10 +100793,13 @@ |
| 100536 | 100793 | pModule = pVtab->pModule; |
| 100537 | 100794 | assert( pModule->xColumn ); |
| 100538 | 100795 | memset(&sContext, 0, sizeof(sContext)); |
| 100539 | 100796 | sContext.pOut = pDest; |
| 100540 | 100797 | sContext.enc = encoding; |
| 100798 | + nullFunc.pUserData = 0; |
| 100799 | + nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE; |
| 100800 | + sContext.pFunc = &nullFunc; |
| 100541 | 100801 | assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 ); |
| 100542 | 100802 | if( pOp->p5 & OPFLAG_NOCHNG ){ |
| 100543 | 100803 | sqlite3VdbeMemSetNull(pDest); |
| 100544 | 100804 | pDest->flags = MEM_Null|MEM_Zero; |
| 100545 | 100805 | pDest->u.nZero = 0; |
| | @@ -100867,10 +101127,46 @@ |
| 100867 | 101127 | case OP_ClrSubtype: { /* in1 */ |
| 100868 | 101128 | pIn1 = &aMem[pOp->p1]; |
| 100869 | 101129 | pIn1->flags &= ~MEM_Subtype; |
| 100870 | 101130 | break; |
| 100871 | 101131 | } |
| 101132 | + |
| 101133 | +/* Opcode: GetSubtype P1 P2 * * * |
| 101134 | +** Synopsis: r[P2] = r[P1].subtype |
| 101135 | +** |
| 101136 | +** Extract the subtype value from register P1 and write that subtype |
| 101137 | +** into register P2. If P1 has no subtype, then P1 gets a NULL. |
| 101138 | +*/ |
| 101139 | +case OP_GetSubtype: { /* in1 out2 */ |
| 101140 | + pIn1 = &aMem[pOp->p1]; |
| 101141 | + pOut = &aMem[pOp->p2]; |
| 101142 | + if( pIn1->flags & MEM_Subtype ){ |
| 101143 | + sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype); |
| 101144 | + }else{ |
| 101145 | + sqlite3VdbeMemSetNull(pOut); |
| 101146 | + } |
| 101147 | + break; |
| 101148 | +} |
| 101149 | + |
| 101150 | +/* Opcode: SetSubtype P1 P2 * * * |
| 101151 | +** Synopsis: r[P2].subtype = r[P1] |
| 101152 | +** |
| 101153 | +** Set the subtype value of register P2 to the integer from register P1. |
| 101154 | +** If P1 is NULL, clear the subtype from p2. |
| 101155 | +*/ |
| 101156 | +case OP_SetSubtype: { /* in1 out2 */ |
| 101157 | + pIn1 = &aMem[pOp->p1]; |
| 101158 | + pOut = &aMem[pOp->p2]; |
| 101159 | + if( pIn1->flags & MEM_Null ){ |
| 101160 | + pOut->flags &= ~MEM_Subtype; |
| 101161 | + }else{ |
| 101162 | + assert( pIn1->flags & MEM_Int ); |
| 101163 | + pOut->flags |= MEM_Subtype; |
| 101164 | + pOut->eSubtype = (u8)(pIn1->u.i & 0xff); |
| 101165 | + } |
| 101166 | + break; |
| 101167 | +} |
| 100872 | 101168 | |
| 100873 | 101169 | /* Opcode: FilterAdd P1 * P3 P4 * |
| 100874 | 101170 | ** Synopsis: filter(P1) += key(P3@P4) |
| 100875 | 101171 | ** |
| 100876 | 101172 | ** Compute a hash on the P4 registers starting with r[P3] and |
| | @@ -105916,10 +106212,11 @@ |
| 105916 | 106212 | |
| 105917 | 106213 | n = pExpr->iColumn; |
| 105918 | 106214 | assert( ExprUseYTab(pExpr) ); |
| 105919 | 106215 | pExTab = pExpr->y.pTab; |
| 105920 | 106216 | assert( pExTab!=0 ); |
| 106217 | + assert( n < pExTab->nCol ); |
| 105921 | 106218 | if( (pExTab->tabFlags & TF_HasGenerated)!=0 |
| 105922 | 106219 | && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0 |
| 105923 | 106220 | ){ |
| 105924 | 106221 | testcase( pExTab->nCol==BMS-1 ); |
| 105925 | 106222 | testcase( pExTab->nCol==BMS ); |
| | @@ -106518,11 +106815,11 @@ |
| 106518 | 106815 | ** (See ticket [b92e5e8ec2cdbaa1]). |
| 106519 | 106816 | ** |
| 106520 | 106817 | ** If a generated column is referenced, set bits for every column |
| 106521 | 106818 | ** of the table. |
| 106522 | 106819 | */ |
| 106523 | | - if( pExpr->iColumn>=0 && pMatch!=0 ){ |
| 106820 | + if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){ |
| 106524 | 106821 | pMatch->colUsed |= sqlite3ExprColUsed(pExpr); |
| 106525 | 106822 | } |
| 106526 | 106823 | |
| 106527 | 106824 | pExpr->op = eNewExprOp; |
| 106528 | 106825 | lookupname_end: |
| | @@ -106983,15 +107280,16 @@ |
| 106983 | 107280 | #endif |
| 106984 | 107281 | pNC2 = pNC; |
| 106985 | 107282 | while( pNC2 |
| 106986 | 107283 | && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0 |
| 106987 | 107284 | ){ |
| 106988 | | - pExpr->op2++; |
| 107285 | + pExpr->op2 += (1 + pNC2->nNestedSelect); |
| 106989 | 107286 | pNC2 = pNC2->pNext; |
| 106990 | 107287 | } |
| 106991 | 107288 | assert( pDef!=0 || IN_RENAME_OBJECT ); |
| 106992 | 107289 | if( pNC2 && pDef ){ |
| 107290 | + pExpr->op2 += pNC2->nNestedSelect; |
| 106993 | 107291 | assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); |
| 106994 | 107292 | assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg ); |
| 106995 | 107293 | testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); |
| 106996 | 107294 | testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 ); |
| 106997 | 107295 | pNC2->ncFlags |= NC_HasAgg |
| | @@ -107546,10 +107844,11 @@ |
| 107546 | 107844 | p->pOrderBy = 0; |
| 107547 | 107845 | } |
| 107548 | 107846 | |
| 107549 | 107847 | /* Recursively resolve names in all subqueries in the FROM clause |
| 107550 | 107848 | */ |
| 107849 | + if( pOuterNC ) pOuterNC->nNestedSelect++; |
| 107551 | 107850 | for(i=0; i<p->pSrc->nSrc; i++){ |
| 107552 | 107851 | SrcItem *pItem = &p->pSrc->a[i]; |
| 107553 | 107852 | if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ |
| 107554 | 107853 | int nRef = pOuterNC ? pOuterNC->nRef : 0; |
| 107555 | 107854 | const char *zSavedContext = pParse->zAuthContext; |
| | @@ -107569,10 +107868,13 @@ |
| 107569 | 107868 | if( pOuterNC ){ |
| 107570 | 107869 | assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef ); |
| 107571 | 107870 | pItem->fg.isCorrelated = (pOuterNC->nRef>nRef); |
| 107572 | 107871 | } |
| 107573 | 107872 | } |
| 107873 | + } |
| 107874 | + if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){ |
| 107875 | + pOuterNC->nNestedSelect--; |
| 107574 | 107876 | } |
| 107575 | 107877 | |
| 107576 | 107878 | /* Set up the local name-context to pass to sqlite3ResolveExprNames() to |
| 107577 | 107879 | ** resolve the result-set expression list. |
| 107578 | 107880 | */ |
| | @@ -109157,13 +109459,11 @@ |
| 109157 | 109459 | assert( pExpr->op==TK_FUNCTION ); |
| 109158 | 109460 | assert( pExpr->pLeft==0 ); |
| 109159 | 109461 | assert( ExprUseXList(pExpr) ); |
| 109160 | 109462 | if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){ |
| 109161 | 109463 | /* Ignore ORDER BY on zero-argument aggregates */ |
| 109162 | | - sqlite3ParserAddCleanup(pParse, |
| 109163 | | - (void(*)(sqlite3*,void*))sqlite3ExprListDelete, |
| 109164 | | - pOrderBy); |
| 109464 | + sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy); |
| 109165 | 109465 | return; |
| 109166 | 109466 | } |
| 109167 | 109467 | if( IsWindowFunc(pExpr) ){ |
| 109168 | 109468 | sqlite3ExprOrderByAggregateError(pParse, pExpr); |
| 109169 | 109469 | sqlite3ExprListDelete(db, pOrderBy); |
| | @@ -109340,10 +109640,13 @@ |
| 109340 | 109640 | } |
| 109341 | 109641 | } |
| 109342 | 109642 | SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ |
| 109343 | 109643 | if( p ) sqlite3ExprDeleteNN(db, p); |
| 109344 | 109644 | } |
| 109645 | +SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){ |
| 109646 | + if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p); |
| 109647 | +} |
| 109345 | 109648 | |
| 109346 | 109649 | /* |
| 109347 | 109650 | ** Clear both elements of an OnOrUsing object |
| 109348 | 109651 | */ |
| 109349 | 109652 | SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){ |
| | @@ -109365,13 +109668,11 @@ |
| 109365 | 109668 | ** |
| 109366 | 109669 | ** The deferred delete is (currently) implemented by adding the |
| 109367 | 109670 | ** pExpr to the pParse->pConstExpr list with a register number of 0. |
| 109368 | 109671 | */ |
| 109369 | 109672 | SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ |
| 109370 | | - sqlite3ParserAddCleanup(pParse, |
| 109371 | | - (void(*)(sqlite3*,void*))sqlite3ExprDelete, |
| 109372 | | - pExpr); |
| 109673 | + sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr); |
| 109373 | 109674 | } |
| 109374 | 109675 | |
| 109375 | 109676 | /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the |
| 109376 | 109677 | ** expression. |
| 109377 | 109678 | */ |
| | @@ -110172,10 +110473,13 @@ |
| 110172 | 110473 | }while( --i>0 ); |
| 110173 | 110474 | sqlite3DbNNFreeNN(db, pList); |
| 110174 | 110475 | } |
| 110175 | 110476 | SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ |
| 110176 | 110477 | if( pList ) exprListDeleteNN(db, pList); |
| 110478 | +} |
| 110479 | +SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){ |
| 110480 | + if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList); |
| 110177 | 110481 | } |
| 110178 | 110482 | |
| 110179 | 110483 | /* |
| 110180 | 110484 | ** Return the bitwise-OR of all Expr.flags fields in the given |
| 110181 | 110485 | ** ExprList. |
| | @@ -114703,17 +115007,18 @@ |
| 114703 | 115007 | return WRC_Continue; |
| 114704 | 115008 | } |
| 114705 | 115009 | case TK_AGG_FUNCTION: { |
| 114706 | 115010 | if( (pNC->ncFlags & NC_InAggFunc)==0 |
| 114707 | 115011 | && pWalker->walkerDepth==pExpr->op2 |
| 115012 | + && pExpr->pAggInfo==0 |
| 114708 | 115013 | ){ |
| 114709 | 115014 | /* Check to see if pExpr is a duplicate of another aggregate |
| 114710 | 115015 | ** function that is already in the pAggInfo structure |
| 114711 | 115016 | */ |
| 114712 | 115017 | struct AggInfo_func *pItem = pAggInfo->aFunc; |
| 114713 | 115018 | for(i=0; i<pAggInfo->nFunc; i++, pItem++){ |
| 114714 | | - if( pItem->pFExpr==pExpr ) break; |
| 115019 | + if( NEVER(pItem->pFExpr==pExpr) ) break; |
| 114715 | 115020 | if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){ |
| 114716 | 115021 | break; |
| 114717 | 115022 | } |
| 114718 | 115023 | } |
| 114719 | 115024 | if( i>=pAggInfo->nFunc ){ |
| | @@ -114752,10 +115057,12 @@ |
| 114752 | 115057 | pItem->bOBPayload = 0; |
| 114753 | 115058 | pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct); |
| 114754 | 115059 | }else{ |
| 114755 | 115060 | pItem->bOBPayload = 1; |
| 114756 | 115061 | } |
| 115062 | + pItem->bUseSubtype = |
| 115063 | + (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0; |
| 114757 | 115064 | }else{ |
| 114758 | 115065 | pItem->iOBTab = -1; |
| 114759 | 115066 | } |
| 114760 | 115067 | if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){ |
| 114761 | 115068 | pItem->iDistinct = pParse->nTab++; |
| | @@ -120856,11 +121163,11 @@ |
| 120856 | 121163 | ** the DEFAULT clause or the AS clause of a generated column. |
| 120857 | 121164 | ** Return NULL if the column has no associated expression. |
| 120858 | 121165 | */ |
| 120859 | 121166 | SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){ |
| 120860 | 121167 | if( pCol->iDflt==0 ) return 0; |
| 120861 | | - if( NEVER(!IsOrdinaryTable(pTab)) ) return 0; |
| 121168 | + if( !IsOrdinaryTable(pTab) ) return 0; |
| 120862 | 121169 | if( NEVER(pTab->u.tab.pDfltList==0) ) return 0; |
| 120863 | 121170 | if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0; |
| 120864 | 121171 | return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr; |
| 120865 | 121172 | } |
| 120866 | 121173 | |
| | @@ -121008,10 +121315,13 @@ |
| 121008 | 121315 | /* Do not delete the table until the reference count reaches zero. */ |
| 121009 | 121316 | assert( db!=0 ); |
| 121010 | 121317 | if( !pTable ) return; |
| 121011 | 121318 | if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return; |
| 121012 | 121319 | deleteTable(db, pTable); |
| 121320 | +} |
| 121321 | +SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){ |
| 121322 | + sqlite3DeleteTable(db, (Table*)pTable); |
| 121013 | 121323 | } |
| 121014 | 121324 | |
| 121015 | 121325 | |
| 121016 | 121326 | /* |
| 121017 | 121327 | ** Unlink the given table from the hash tables and the delete the |
| | @@ -121546,11 +121856,12 @@ |
| 121546 | 121856 | #endif |
| 121547 | 121857 | |
| 121548 | 121858 | /* |
| 121549 | 121859 | ** Clean up the data structures associated with the RETURNING clause. |
| 121550 | 121860 | */ |
| 121551 | | -static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){ |
| 121861 | +static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){ |
| 121862 | + Returning *pRet = (Returning*)pArg; |
| 121552 | 121863 | Hash *pHash; |
| 121553 | 121864 | pHash = &(db->aDb[1].pSchema->trigHash); |
| 121554 | 121865 | sqlite3HashInsert(pHash, pRet->zName, 0); |
| 121555 | 121866 | sqlite3ExprListDelete(db, pRet->pReturnEL); |
| 121556 | 121867 | sqlite3DbFree(db, pRet); |
| | @@ -121588,12 +121899,11 @@ |
| 121588 | 121899 | return; |
| 121589 | 121900 | } |
| 121590 | 121901 | pParse->u1.pReturning = pRet; |
| 121591 | 121902 | pRet->pParse = pParse; |
| 121592 | 121903 | pRet->pReturnEL = pList; |
| 121593 | | - sqlite3ParserAddCleanup(pParse, |
| 121594 | | - (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet); |
| 121904 | + sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet); |
| 121595 | 121905 | testcase( pParse->earlyCleanup ); |
| 121596 | 121906 | if( db->mallocFailed ) return; |
| 121597 | 121907 | sqlite3_snprintf(sizeof(pRet->zName), pRet->zName, |
| 121598 | 121908 | "sqlite_returning_%p", pParse); |
| 121599 | 121909 | pRet->retTrig.zName = pRet->zName; |
| | @@ -125827,10 +126137,13 @@ |
| 125827 | 126137 | for(i=0; i<pWith->nCte; i++){ |
| 125828 | 126138 | cteClear(db, &pWith->a[i]); |
| 125829 | 126139 | } |
| 125830 | 126140 | sqlite3DbFree(db, pWith); |
| 125831 | 126141 | } |
| 126142 | +} |
| 126143 | +SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){ |
| 126144 | + sqlite3WithDelete(db, (With*)pWith); |
| 125832 | 126145 | } |
| 125833 | 126146 | #endif /* !defined(SQLITE_OMIT_CTE) */ |
| 125834 | 126147 | |
| 125835 | 126148 | /************** End of build.c ***********************************************/ |
| 125836 | 126149 | /************** Begin file callback.c ****************************************/ |
| | @@ -139053,11 +139366,12 @@ |
| 139053 | 139366 | if( NEVER(pVTab==0) ) continue; |
| 139054 | 139367 | if( NEVER(pVTab->pModule==0) ) continue; |
| 139055 | 139368 | if( pVTab->pModule->iVersion<4 ) continue; |
| 139056 | 139369 | if( pVTab->pModule->xIntegrity==0 ) continue; |
| 139057 | 139370 | sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick); |
| 139058 | | - sqlite3VdbeAppendP4(v, pTab, P4_TABLE); |
| 139371 | + pTab->nTabRef++; |
| 139372 | + sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF); |
| 139059 | 139373 | a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v); |
| 139060 | 139374 | integrityCheckResultRow(v); |
| 139061 | 139375 | sqlite3VdbeJumpHere(v, a1); |
| 139062 | 139376 | #endif |
| 139063 | 139377 | continue; |
| | @@ -141080,10 +141394,11 @@ |
| 141080 | 141394 | sqlite3BtreeLeaveAll(db); |
| 141081 | 141395 | rc = sqlite3ApiExit(db, rc); |
| 141082 | 141396 | assert( (rc&db->errMask)==rc ); |
| 141083 | 141397 | db->busyHandler.nBusy = 0; |
| 141084 | 141398 | sqlite3_mutex_leave(db->mutex); |
| 141399 | + assert( rc==SQLITE_OK || (*ppStmt)==0 ); |
| 141085 | 141400 | return rc; |
| 141086 | 141401 | } |
| 141087 | 141402 | |
| 141088 | 141403 | |
| 141089 | 141404 | /* |
| | @@ -141476,10 +141791,13 @@ |
| 141476 | 141791 | /* |
| 141477 | 141792 | ** Delete the given Select structure and all of its substructures. |
| 141478 | 141793 | */ |
| 141479 | 141794 | SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){ |
| 141480 | 141795 | if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); |
| 141796 | +} |
| 141797 | +SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){ |
| 141798 | + if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1); |
| 141481 | 141799 | } |
| 141482 | 141800 | |
| 141483 | 141801 | /* |
| 141484 | 141802 | ** Return a pointer to the right-most SELECT statement in a compound. |
| 141485 | 141803 | */ |
| | @@ -144497,13 +144815,11 @@ |
| 144497 | 144815 | |
| 144498 | 144816 | multi_select_end: |
| 144499 | 144817 | pDest->iSdst = dest.iSdst; |
| 144500 | 144818 | pDest->nSdst = dest.nSdst; |
| 144501 | 144819 | if( pDelete ){ |
| 144502 | | - sqlite3ParserAddCleanup(pParse, |
| 144503 | | - (void(*)(sqlite3*,void*))sqlite3SelectDelete, |
| 144504 | | - pDelete); |
| 144820 | + sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); |
| 144505 | 144821 | } |
| 144506 | 144822 | return rc; |
| 144507 | 144823 | } |
| 144508 | 144824 | #endif /* SQLITE_OMIT_COMPOUND_SELECT */ |
| 144509 | 144825 | |
| | @@ -145050,12 +145366,11 @@ |
| 145050 | 145366 | sqlite3VdbeResolveLabel(v, labelEnd); |
| 145051 | 145367 | |
| 145052 | 145368 | /* Make arrangements to free the 2nd and subsequent arms of the compound |
| 145053 | 145369 | ** after the parse has finished */ |
| 145054 | 145370 | if( pSplit->pPrior ){ |
| 145055 | | - sqlite3ParserAddCleanup(pParse, |
| 145056 | | - (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior); |
| 145371 | + sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior); |
| 145057 | 145372 | } |
| 145058 | 145373 | pSplit->pPrior = pPrior; |
| 145059 | 145374 | pPrior->pNext = pSplit; |
| 145060 | 145375 | sqlite3ExprListDelete(db, pPrior->pOrderBy); |
| 145061 | 145376 | pPrior->pOrderBy = 0; |
| | @@ -145872,13 +146187,11 @@ |
| 145872 | 146187 | */ |
| 145873 | 146188 | if( ALWAYS(pSubitem->pTab!=0) ){ |
| 145874 | 146189 | Table *pTabToDel = pSubitem->pTab; |
| 145875 | 146190 | if( pTabToDel->nTabRef==1 ){ |
| 145876 | 146191 | Parse *pToplevel = sqlite3ParseToplevel(pParse); |
| 145877 | | - sqlite3ParserAddCleanup(pToplevel, |
| 145878 | | - (void(*)(sqlite3*,void*))sqlite3DeleteTable, |
| 145879 | | - pTabToDel); |
| 146192 | + sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); |
| 145880 | 146193 | testcase( pToplevel->earlyCleanup ); |
| 145881 | 146194 | }else{ |
| 145882 | 146195 | pTabToDel->nTabRef--; |
| 145883 | 146196 | } |
| 145884 | 146197 | pSubitem->pTab = 0; |
| | @@ -146921,12 +147234,11 @@ |
| 146921 | 147234 | ** calling this routine, Instead, use only the return value. |
| 146922 | 147235 | */ |
| 146923 | 147236 | SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ |
| 146924 | 147237 | if( pWith ){ |
| 146925 | 147238 | if( bFree ){ |
| 146926 | | - pWith = (With*)sqlite3ParserAddCleanup(pParse, |
| 146927 | | - (void(*)(sqlite3*,void*))sqlite3WithDelete, |
| 147239 | + pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric, |
| 146928 | 147240 | pWith); |
| 146929 | 147241 | if( pWith==0 ) return 0; |
| 146930 | 147242 | } |
| 146931 | 147243 | if( pParse->nErr==0 ){ |
| 146932 | 147244 | assert( pParse->pWith!=pWith ); |
| | @@ -147955,19 +148267,23 @@ |
| 147955 | 148267 | KeyInfo *pKeyInfo; |
| 147956 | 148268 | int nExtra = 0; |
| 147957 | 148269 | assert( pFunc->pFExpr->pLeft!=0 ); |
| 147958 | 148270 | assert( pFunc->pFExpr->pLeft->op==TK_ORDER ); |
| 147959 | 148271 | assert( ExprUseXList(pFunc->pFExpr->pLeft) ); |
| 148272 | + assert( pFunc->pFunc!=0 ); |
| 147960 | 148273 | pOBList = pFunc->pFExpr->pLeft->x.pList; |
| 147961 | 148274 | if( !pFunc->bOBUnique ){ |
| 147962 | 148275 | nExtra++; /* One extra column for the OP_Sequence */ |
| 147963 | 148276 | } |
| 147964 | 148277 | if( pFunc->bOBPayload ){ |
| 147965 | 148278 | /* extra columns for the function arguments */ |
| 147966 | 148279 | assert( ExprUseXList(pFunc->pFExpr) ); |
| 147967 | 148280 | nExtra += pFunc->pFExpr->x.pList->nExpr; |
| 147968 | 148281 | } |
| 148282 | + if( pFunc->bUseSubtype ){ |
| 148283 | + nExtra += pFunc->pFExpr->x.pList->nExpr; |
| 148284 | + } |
| 147969 | 148285 | pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra); |
| 147970 | 148286 | if( !pFunc->bOBUnique && pParse->nErr==0 ){ |
| 147971 | 148287 | pKeyInfo->nKeyField++; |
| 147972 | 148288 | } |
| 147973 | 148289 | sqlite3VdbeAddOp4(v, OP_OpenEphemeral, |
| | @@ -147990,20 +148306,21 @@ |
| 147990 | 148306 | for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ |
| 147991 | 148307 | ExprList *pList; |
| 147992 | 148308 | assert( ExprUseXList(pF->pFExpr) ); |
| 147993 | 148309 | pList = pF->pFExpr->x.pList; |
| 147994 | 148310 | if( pF->iOBTab>=0 ){ |
| 147995 | | - /* For an ORDER BY aggregate, calls to OP_AggStep where deferred and |
| 147996 | | - ** all content was stored in emphermal table pF->iOBTab. Extract that |
| 147997 | | - ** content now (in ORDER BY order) and make all calls to OP_AggStep |
| 148311 | + /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs |
| 148312 | + ** were stored in emphermal table pF->iOBTab. Here, we extract those |
| 148313 | + ** inputs (in ORDER BY order) and make all calls to OP_AggStep |
| 147998 | 148314 | ** before doing the OP_AggFinal call. */ |
| 147999 | 148315 | int iTop; /* Start of loop for extracting columns */ |
| 148000 | 148316 | int nArg; /* Number of columns to extract */ |
| 148001 | 148317 | int nKey; /* Key columns to be skipped */ |
| 148002 | 148318 | int regAgg; /* Extract into this array */ |
| 148003 | 148319 | int j; /* Loop counter */ |
| 148004 | 148320 | |
| 148321 | + assert( pF->pFunc!=0 ); |
| 148005 | 148322 | nArg = pList->nExpr; |
| 148006 | 148323 | regAgg = sqlite3GetTempRange(pParse, nArg); |
| 148007 | 148324 | |
| 148008 | 148325 | if( pF->bOBPayload==0 ){ |
| 148009 | 148326 | nKey = 0; |
| | @@ -148016,10 +148333,19 @@ |
| 148016 | 148333 | } |
| 148017 | 148334 | iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v); |
| 148018 | 148335 | for(j=nArg-1; j>=0; j--){ |
| 148019 | 148336 | sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j); |
| 148020 | 148337 | } |
| 148338 | + if( pF->bUseSubtype ){ |
| 148339 | + int regSubtype = sqlite3GetTempReg(pParse); |
| 148340 | + int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0); |
| 148341 | + for(j=nArg-1; j>=0; j--){ |
| 148342 | + sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype); |
| 148343 | + sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j); |
| 148344 | + } |
| 148345 | + sqlite3ReleaseTempReg(pParse, regSubtype); |
| 148346 | + } |
| 148021 | 148347 | sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i)); |
| 148022 | 148348 | sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); |
| 148023 | 148349 | sqlite3VdbeChangeP5(v, (u8)nArg); |
| 148024 | 148350 | sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v); |
| 148025 | 148351 | sqlite3VdbeJumpHere(v, iTop); |
| | @@ -148070,10 +148396,11 @@ |
| 148070 | 148396 | int regAggSz = 0; |
| 148071 | 148397 | int regDistinct = 0; |
| 148072 | 148398 | ExprList *pList; |
| 148073 | 148399 | assert( ExprUseXList(pF->pFExpr) ); |
| 148074 | 148400 | assert( !IsWindowFunc(pF->pFExpr) ); |
| 148401 | + assert( pF->pFunc!=0 ); |
| 148075 | 148402 | pList = pF->pFExpr->x.pList; |
| 148076 | 148403 | if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){ |
| 148077 | 148404 | Expr *pFilter = pF->pFExpr->y.pWin->pFilter; |
| 148078 | 148405 | if( pAggInfo->nAccumulator |
| 148079 | 148406 | && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) |
| | @@ -148113,10 +148440,13 @@ |
| 148113 | 148440 | if( !pF->bOBUnique ){ |
| 148114 | 148441 | regAggSz++; /* One register for OP_Sequence */ |
| 148115 | 148442 | } |
| 148116 | 148443 | if( pF->bOBPayload ){ |
| 148117 | 148444 | regAggSz += nArg; |
| 148445 | + } |
| 148446 | + if( pF->bUseSubtype ){ |
| 148447 | + regAggSz += nArg; |
| 148118 | 148448 | } |
| 148119 | 148449 | regAggSz++; /* One extra register to hold result of MakeRecord */ |
| 148120 | 148450 | regAgg = sqlite3GetTempRange(pParse, regAggSz); |
| 148121 | 148451 | regDistinct = regAgg; |
| 148122 | 148452 | sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP); |
| | @@ -148126,10 +148456,18 @@ |
| 148126 | 148456 | jj++; |
| 148127 | 148457 | } |
| 148128 | 148458 | if( pF->bOBPayload ){ |
| 148129 | 148459 | regDistinct = regAgg+jj; |
| 148130 | 148460 | sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP); |
| 148461 | + jj += nArg; |
| 148462 | + } |
| 148463 | + if( pF->bUseSubtype ){ |
| 148464 | + int kk; |
| 148465 | + int regBase = pF->bOBPayload ? regDistinct : regAgg; |
| 148466 | + for(kk=0; kk<nArg; kk++, jj++){ |
| 148467 | + sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj); |
| 148468 | + } |
| 148131 | 148469 | } |
| 148132 | 148470 | }else if( pList ){ |
| 148133 | 148471 | nArg = pList->nExpr; |
| 148134 | 148472 | regAgg = sqlite3GetTempRange(pParse, nArg); |
| 148135 | 148473 | regDistinct = regAgg; |
| | @@ -148330,11 +148668,12 @@ |
| 148330 | 148668 | } |
| 148331 | 148669 | |
| 148332 | 148670 | /* |
| 148333 | 148671 | ** Deallocate a single AggInfo object |
| 148334 | 148672 | */ |
| 148335 | | -static void agginfoFree(sqlite3 *db, AggInfo *p){ |
| 148673 | +static void agginfoFree(sqlite3 *db, void *pArg){ |
| 148674 | + AggInfo *p = (AggInfo*)pArg; |
| 148336 | 148675 | sqlite3DbFree(db, p->aCol); |
| 148337 | 148676 | sqlite3DbFree(db, p->aFunc); |
| 148338 | 148677 | sqlite3DbFreeNN(db, p); |
| 148339 | 148678 | } |
| 148340 | 148679 | |
| | @@ -148584,13 +148923,12 @@ |
| 148584 | 148923 | TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n")); |
| 148585 | 148924 | if( sqlite3TreeTrace & 0x800 ){ |
| 148586 | 148925 | sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY"); |
| 148587 | 148926 | } |
| 148588 | 148927 | #endif |
| 148589 | | - sqlite3ParserAddCleanup(pParse, |
| 148590 | | - (void(*)(sqlite3*,void*))sqlite3ExprListDelete, |
| 148591 | | - p->pOrderBy); |
| 148928 | + sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, |
| 148929 | + p->pOrderBy); |
| 148592 | 148930 | testcase( pParse->earlyCleanup ); |
| 148593 | 148931 | p->pOrderBy = 0; |
| 148594 | 148932 | } |
| 148595 | 148933 | p->selFlags &= ~SF_Distinct; |
| 148596 | 148934 | p->selFlags |= SF_NoopOrderBy; |
| | @@ -148778,13 +149116,12 @@ |
| 148778 | 149116 | && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */ |
| 148779 | 149117 | && OptimizationEnabled(db, SQLITE_OmitOrderBy) |
| 148780 | 149118 | ){ |
| 148781 | 149119 | TREETRACE(0x800,pParse,p, |
| 148782 | 149120 | ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1)); |
| 148783 | | - sqlite3ParserAddCleanup(pParse, |
| 148784 | | - (void(*)(sqlite3*,void*))sqlite3ExprListDelete, |
| 148785 | | - pSub->pOrderBy); |
| 149121 | + sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, |
| 149122 | + pSub->pOrderBy); |
| 148786 | 149123 | pSub->pOrderBy = 0; |
| 148787 | 149124 | } |
| 148788 | 149125 | |
| 148789 | 149126 | /* If the outer query contains a "complex" result set (that is, |
| 148790 | 149127 | ** if the result set of the outer query uses functions or subqueries) |
| | @@ -149309,12 +149646,11 @@ |
| 149309 | 149646 | ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the |
| 149310 | 149647 | ** SELECT statement. |
| 149311 | 149648 | */ |
| 149312 | 149649 | pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) ); |
| 149313 | 149650 | if( pAggInfo ){ |
| 149314 | | - sqlite3ParserAddCleanup(pParse, |
| 149315 | | - (void(*)(sqlite3*,void*))agginfoFree, pAggInfo); |
| 149651 | + sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo); |
| 149316 | 149652 | testcase( pParse->earlyCleanup ); |
| 149317 | 149653 | } |
| 149318 | 149654 | if( db->mallocFailed ){ |
| 149319 | 149655 | goto select_end; |
| 149320 | 149656 | } |
| | @@ -160987,16 +161323,26 @@ |
| 160987 | 161323 | int iEnd = sqlite3VdbeCurrentAddr(v); |
| 160988 | 161324 | if( pParse->db->mallocFailed ) return; |
| 160989 | 161325 | for(; iStart<iEnd; iStart++, pOp++){ |
| 160990 | 161326 | if( pOp->p1!=iTabCur ) continue; |
| 160991 | 161327 | if( pOp->opcode==OP_Column ){ |
| 161328 | +#ifdef SQLITE_DEBUG |
| 161329 | + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ |
| 161330 | + printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart); |
| 161331 | + } |
| 161332 | +#endif |
| 160992 | 161333 | pOp->opcode = OP_Copy; |
| 160993 | 161334 | pOp->p1 = pOp->p2 + iRegister; |
| 160994 | 161335 | pOp->p2 = pOp->p3; |
| 160995 | 161336 | pOp->p3 = 0; |
| 160996 | 161337 | pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */ |
| 160997 | 161338 | }else if( pOp->opcode==OP_Rowid ){ |
| 161339 | +#ifdef SQLITE_DEBUG |
| 161340 | + if( pParse->db->flags & SQLITE_VdbeAddopTrace ){ |
| 161341 | + printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart); |
| 161342 | + } |
| 161343 | +#endif |
| 160998 | 161344 | pOp->opcode = OP_Sequence; |
| 160999 | 161345 | pOp->p1 = iAutoidxCur; |
| 161000 | 161346 | #ifdef SQLITE_ALLOW_ROWID_IN_VIEW |
| 161001 | 161347 | if( iAutoidxCur==0 ){ |
| 161002 | 161348 | pOp->opcode = OP_Null; |
| | @@ -162319,11 +162665,12 @@ |
| 162319 | 162665 | nNew = sqlite3LogEst(iUpper - iLower); |
| 162320 | 162666 | /* TUNING: If both iUpper and iLower are derived from the same |
| 162321 | 162667 | ** sample, then assume they are 4x more selective. This brings |
| 162322 | 162668 | ** the estimated selectivity more in line with what it would be |
| 162323 | 162669 | ** if estimated without the use of STAT4 tables. */ |
| 162324 | | - if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); |
| 162670 | + if( iLwrIdx==iUprIdx ){ nNew -= 20; } |
| 162671 | + assert( 20==sqlite3LogEst(4) ); |
| 162325 | 162672 | }else{ |
| 162326 | 162673 | nNew = 10; assert( 10==sqlite3LogEst(2) ); |
| 162327 | 162674 | } |
| 162328 | 162675 | if( nNew<nOut ){ |
| 162329 | 162676 | nOut = nNew; |
| | @@ -182234,10 +182581,32 @@ |
| 182234 | 182581 | rc = SQLITE_NOTFOUND; |
| 182235 | 182582 | } |
| 182236 | 182583 | break; |
| 182237 | 182584 | } |
| 182238 | 182585 | #endif |
| 182586 | + |
| 182587 | + /* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff); |
| 182588 | + ** |
| 182589 | + ** Activate or deactivate validation of JSONB that is generated from |
| 182590 | + ** text. Off by default, as the validation is slow. Validation is |
| 182591 | + ** only available if compiled using SQLITE_DEBUG. |
| 182592 | + ** |
| 182593 | + ** If onOff is initially 1, then turn it on. If onOff is initially |
| 182594 | + ** off, turn it off. If onOff is initially -1, then change onOff |
| 182595 | + ** to be the current setting. |
| 182596 | + */ |
| 182597 | + case SQLITE_TESTCTRL_JSON_SELFCHECK: { |
| 182598 | +#if defined(SQLITE_DEBUG) |
| 182599 | + int *pOnOff = va_arg(ap, int*); |
| 182600 | + if( *pOnOff<0 ){ |
| 182601 | + *pOnOff = sqlite3Config.bJsonSelfcheck; |
| 182602 | + }else{ |
| 182603 | + sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff); |
| 182604 | + } |
| 182605 | +#endif |
| 182606 | + break; |
| 182607 | + } |
| 182239 | 182608 | } |
| 182240 | 182609 | va_end(ap); |
| 182241 | 182610 | #endif /* SQLITE_UNTESTABLE */ |
| 182242 | 182611 | return rc; |
| 182243 | 182612 | } |
| | @@ -202648,28 +203017,146 @@ |
| 202648 | 203017 | ** May you find forgiveness for yourself and forgive others. |
| 202649 | 203018 | ** May you share freely, never taking more than you give. |
| 202650 | 203019 | ** |
| 202651 | 203020 | ****************************************************************************** |
| 202652 | 203021 | ** |
| 202653 | | -** This SQLite JSON functions. |
| 203022 | +** SQLite JSON functions. |
| 202654 | 203023 | ** |
| 202655 | 203024 | ** This file began as an extension in ext/misc/json1.c in 2015. That |
| 202656 | 203025 | ** extension proved so useful that it has now been moved into the core. |
| 202657 | 203026 | ** |
| 202658 | | -** For the time being, all JSON is stored as pure text. (We might add |
| 202659 | | -** a JSONB type in the future which stores a binary encoding of JSON in |
| 202660 | | -** a BLOB, but there is no support for JSONB in the current implementation. |
| 202661 | | -** This implementation parses JSON text at 250 MB/s, so it is hard to see |
| 202662 | | -** how JSONB might improve on that.) |
| 203027 | +** The original design stored all JSON as pure text, canonical RFC-8259. |
| 203028 | +** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16). |
| 203029 | +** All generated JSON text still conforms strictly to RFC-8259, but text |
| 203030 | +** with JSON-5 extensions is accepted as input. |
| 203031 | +** |
| 203032 | +** Beginning with version 3.45.0 (pending), these routines also accept |
| 203033 | +** BLOB values that have JSON encoded using a binary representation we |
| 203034 | +** call JSONB. The name JSONB comes from PostgreSQL, however the on-disk |
| 203035 | +** format SQLite JSONB is completely different and incompatible with |
| 203036 | +** PostgreSQL JSONB. |
| 203037 | +** |
| 203038 | +** Decoding and interpreting JSONB is still O(N) where N is the size of |
| 203039 | +** the input, the same as text JSON. However, the constant of proportionality |
| 203040 | +** for JSONB is much smaller due to faster parsing. The size of each |
| 203041 | +** element in JSONB is encoded in its header, so there is no need to search |
| 203042 | +** for delimiters using persnickety syntax rules. JSONB seems to be about |
| 203043 | +** 3x faster than text JSON as a result. JSONB is also tends to be slightly |
| 203044 | +** smaller than text JSON, by 5% or 10%, but there are corner cases where |
| 203045 | +** JSONB can be slightly larger. So you are not far mistaken to say that |
| 203046 | +** a JSONB blob is the same size as the equivalent RFC-8259 text. |
| 203047 | +** |
| 203048 | +** |
| 203049 | +** THE JSONB ENCODING: |
| 203050 | +** |
| 203051 | +** Every JSON element is encoded in JSONB as a header and a payload. |
| 203052 | +** The header is between 1 and 9 bytes in size. The payload is zero |
| 203053 | +** or more bytes. |
| 203054 | +** |
| 203055 | +** The lower 4 bits of the first byte of the header determines the |
| 203056 | +** element type: |
| 203057 | +** |
| 203058 | +** 0: NULL |
| 203059 | +** 1: TRUE |
| 203060 | +** 2: FALSE |
| 203061 | +** 3: INT -- RFC-8259 integer literal |
| 203062 | +** 4: INT5 -- JSON5 integer literal |
| 203063 | +** 5: FLOAT -- RFC-8259 floating point literal |
| 203064 | +** 6: FLOAT5 -- JSON5 floating point literal |
| 203065 | +** 7: TEXT -- Text literal acceptable to both SQL and JSON |
| 203066 | +** 8: TEXTJ -- Text containing RFC-8259 escapes |
| 203067 | +** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes |
| 203068 | +** 10: TEXTRAW -- Text containing unescaped syntax characters |
| 203069 | +** 11: ARRAY |
| 203070 | +** 12: OBJECT |
| 203071 | +** |
| 203072 | +** The other three possible values (13-15) are reserved for future |
| 203073 | +** enhancements. |
| 203074 | +** |
| 203075 | +** The upper 4 bits of the first byte determine the size of the header |
| 203076 | +** and sometimes also the size of the payload. If X is the first byte |
| 203077 | +** of the element and if X>>4 is between 0 and 11, then the payload |
| 203078 | +** will be that many bytes in size and the header is exactly one byte |
| 203079 | +** in size. Other four values for X>>4 (12-15) indicate that the header |
| 203080 | +** is more than one byte in size and that the payload size is determined |
| 203081 | +** by the remainder of the header, interpreted as a unsigned big-endian |
| 203082 | +** integer. |
| 203083 | +** |
| 203084 | +** Value of X>>4 Size integer Total header size |
| 203085 | +** ------------- -------------------- ----------------- |
| 203086 | +** 12 1 byte (0-255) 2 |
| 203087 | +** 13 2 byte (0-65535) 3 |
| 203088 | +** 14 4 byte (0-4294967295) 5 |
| 203089 | +** 15 8 byte (0-1.8e19) 9 |
| 203090 | +** |
| 203091 | +** The payload size need not be expressed in its minimal form. For example, |
| 203092 | +** if the payload size is 10, the size can be expressed in any of 5 different |
| 203093 | +** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte, |
| 203094 | +** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by |
| 203095 | +** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and |
| 203096 | +** a single byte of 0x0a. The shorter forms are preferred, of course, but |
| 203097 | +** sometimes when generating JSONB, the payload size is not known in advance |
| 203098 | +** and it is convenient to reserve sufficient header space to cover the |
| 203099 | +** largest possible payload size and then come back later and patch up |
| 203100 | +** the size when it becomes known, resulting in a non-minimal encoding. |
| 203101 | +** |
| 203102 | +** The value (X>>4)==15 is not actually used in the current implementation |
| 203103 | +** (as SQLite is currently unable handle BLOBs larger than about 2GB) |
| 203104 | +** but is included in the design to allow for future enhancements. |
| 203105 | +** |
| 203106 | +** The payload follows the header. NULL, TRUE, and FALSE have no payload and |
| 203107 | +** their payload size must always be zero. The payload for INT, INT5, |
| 203108 | +** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the |
| 203109 | +** "..." or '...' delimiters are omitted from the various text encodings. |
| 203110 | +** The payload for ARRAY and OBJECT is a list of additional elements that |
| 203111 | +** are the content for the array or object. The payload for an OBJECT |
| 203112 | +** must be an even number of elements. The first element of each pair is |
| 203113 | +** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW. |
| 203114 | +** |
| 203115 | +** A valid JSONB blob consists of a single element, as described above. |
| 203116 | +** Usually this will be an ARRAY or OBJECT element which has many more |
| 203117 | +** elements as its content. But the overall blob is just a single element. |
| 203118 | +** |
| 203119 | +** Input validation for JSONB blobs simply checks that the element type |
| 203120 | +** code is between 0 and 12 and that the total size of the element |
| 203121 | +** (header plus payload) is the same as the size of the BLOB. If those |
| 203122 | +** checks are true, the BLOB is assumed to be JSONB and processing continues. |
| 203123 | +** Errors are only raised if some other miscoding is discovered during |
| 203124 | +** processing. |
| 202663 | 203125 | */ |
| 202664 | 203126 | #ifndef SQLITE_OMIT_JSON |
| 202665 | 203127 | /* #include "sqliteInt.h" */ |
| 202666 | 203128 | |
| 203129 | +/* JSONB element types |
| 203130 | +*/ |
| 203131 | +#define JSONB_NULL 0 /* "null" */ |
| 203132 | +#define JSONB_TRUE 1 /* "true" */ |
| 203133 | +#define JSONB_FALSE 2 /* "false" */ |
| 203134 | +#define JSONB_INT 3 /* integer acceptable to JSON and SQL */ |
| 203135 | +#define JSONB_INT5 4 /* integer in 0x000 notation */ |
| 203136 | +#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */ |
| 203137 | +#define JSONB_FLOAT5 6 /* float with JSON5 extensions */ |
| 203138 | +#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */ |
| 203139 | +#define JSONB_TEXTJ 8 /* Text with JSON escapes */ |
| 203140 | +#define JSONB_TEXT5 9 /* Text with JSON-5 escape */ |
| 203141 | +#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */ |
| 203142 | +#define JSONB_ARRAY 11 /* An array */ |
| 203143 | +#define JSONB_OBJECT 12 /* An object */ |
| 203144 | + |
| 203145 | +/* Human-readable names for the JSONB values. The index for each |
| 203146 | +** string must correspond to the JSONB_* integer above. |
| 203147 | +*/ |
| 203148 | +static const char * const jsonbType[] = { |
| 203149 | + "null", "true", "false", "integer", "integer", |
| 203150 | + "real", "real", "text", "text", "text", |
| 203151 | + "text", "array", "object", "", "", "", "" |
| 203152 | +}; |
| 203153 | + |
| 202667 | 203154 | /* |
| 202668 | 203155 | ** Growing our own isspace() routine this way is twice as fast as |
| 202669 | 203156 | ** the library isspace() function, resulting in a 7% overall performance |
| 202670 | | -** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). |
| 203157 | +** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). |
| 202671 | 203158 | */ |
| 202672 | 203159 | static const char jsonIsSpace[] = { |
| 202673 | 203160 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, |
| 202674 | 203161 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202675 | 203162 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| | @@ -202686,15 +203173,23 @@ |
| 202686 | 203173 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202687 | 203174 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202688 | 203175 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202689 | 203176 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202690 | 203177 | }; |
| 202691 | | -#define fast_isspace(x) (jsonIsSpace[(unsigned char)x]) |
| 203178 | +#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) |
| 202692 | 203179 | |
| 202693 | 203180 | /* |
| 202694 | | -** Characters that are special to JSON. Control charaters, |
| 202695 | | -** '"' and '\\'. |
| 203181 | +** The set of all space characters recognized by jsonIsspace(). |
| 203182 | +** Useful as the second argument to strspn(). |
| 203183 | +*/ |
| 203184 | +static const char jsonSpaces[] = "\011\012\015\040"; |
| 203185 | + |
| 203186 | +/* |
| 203187 | +** Characters that are special to JSON. Control characters, |
| 203188 | +** '"' and '\\' and '\''. Actually, '\'' is not special to |
| 203189 | +** canonical JSON, but it is special in JSON-5, so we include |
| 203190 | +** it in the set of special characters. |
| 202696 | 203191 | */ |
| 202697 | 203192 | static const char jsonIsOk[256] = { |
| 202698 | 203193 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202699 | 203194 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 202700 | 203195 | 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| | @@ -202712,247 +203207,353 @@ |
| 202712 | 203207 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 202713 | 203208 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 202714 | 203209 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 |
| 202715 | 203210 | }; |
| 202716 | 203211 | |
| 202717 | | - |
| 202718 | | -#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) |
| 202719 | | -# define VVA(X) |
| 202720 | | -#else |
| 202721 | | -# define VVA(X) X |
| 202722 | | -#endif |
| 202723 | | - |
| 202724 | 203212 | /* Objects */ |
| 203213 | +typedef struct JsonCache JsonCache; |
| 202725 | 203214 | typedef struct JsonString JsonString; |
| 202726 | | -typedef struct JsonNode JsonNode; |
| 202727 | 203215 | typedef struct JsonParse JsonParse; |
| 202728 | | -typedef struct JsonCleanup JsonCleanup; |
| 203216 | + |
| 203217 | +/* |
| 203218 | +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() |
| 203219 | +*/ |
| 203220 | +#define JSON_CACHE_ID (-429938) /* Cache entry */ |
| 203221 | +#define JSON_CACHE_SIZE 4 /* Max number of cache entries */ |
| 203222 | + |
| 203223 | +/* A cache mapping JSON text into JSONB blobs. |
| 203224 | +** |
| 203225 | +** Each cache entry is a JsonParse object with the following restrictions: |
| 203226 | +** |
| 203227 | +** * The bReadOnly flag must be set |
| 203228 | +** |
| 203229 | +** * The aBlob[] array must be owned by the JsonParse object. In other |
| 203230 | +** words, nBlobAlloc must be non-zero. |
| 203231 | +** |
| 203232 | +** * zJson must be an RCStr. In other words bJsonIsRCStr must be true. |
| 203233 | +*/ |
| 203234 | +struct JsonCache { |
| 203235 | + sqlite3 *db; /* Database connection */ |
| 203236 | + int nUsed; /* Number of active entries in the cache */ |
| 203237 | + JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */ |
| 203238 | +}; |
| 202729 | 203239 | |
| 202730 | 203240 | /* An instance of this object represents a JSON string |
| 202731 | 203241 | ** under construction. Really, this is a generic string accumulator |
| 202732 | 203242 | ** that can be and is used to create strings other than JSON. |
| 203243 | +** |
| 203244 | +** If the generated string is longer than will fit into the zSpace[] buffer, |
| 203245 | +** then it will be an RCStr string. This aids with caching of large |
| 203246 | +** JSON strings. |
| 202733 | 203247 | */ |
| 202734 | 203248 | struct JsonString { |
| 202735 | 203249 | sqlite3_context *pCtx; /* Function context - put error messages here */ |
| 202736 | 203250 | char *zBuf; /* Append JSON content here */ |
| 202737 | 203251 | u64 nAlloc; /* Bytes of storage available in zBuf[] */ |
| 202738 | 203252 | u64 nUsed; /* Bytes of zBuf[] currently used */ |
| 202739 | 203253 | u8 bStatic; /* True if zBuf is static space */ |
| 202740 | | - u8 bErr; /* True if an error has been encountered */ |
| 203254 | + u8 eErr; /* True if an error has been encountered */ |
| 202741 | 203255 | char zSpace[100]; /* Initial static space */ |
| 202742 | 203256 | }; |
| 202743 | 203257 | |
| 202744 | | -/* A deferred cleanup task. A list of JsonCleanup objects might be |
| 202745 | | -** run when the JsonParse object is destroyed. |
| 202746 | | -*/ |
| 202747 | | -struct JsonCleanup { |
| 202748 | | - JsonCleanup *pJCNext; /* Next in a list */ |
| 202749 | | - void (*xOp)(void*); /* Routine to run */ |
| 202750 | | - void *pArg; /* Argument to xOp() */ |
| 202751 | | -}; |
| 202752 | | - |
| 202753 | | -/* JSON type values |
| 202754 | | -*/ |
| 202755 | | -#define JSON_SUBST 0 /* Special edit node. Uses u.iPrev */ |
| 202756 | | -#define JSON_NULL 1 |
| 202757 | | -#define JSON_TRUE 2 |
| 202758 | | -#define JSON_FALSE 3 |
| 202759 | | -#define JSON_INT 4 |
| 202760 | | -#define JSON_REAL 5 |
| 202761 | | -#define JSON_STRING 6 |
| 202762 | | -#define JSON_ARRAY 7 |
| 202763 | | -#define JSON_OBJECT 8 |
| 202764 | | - |
| 202765 | | -/* The "subtype" set for JSON values */ |
| 203258 | +/* Allowed values for JsonString.eErr */ |
| 203259 | +#define JSTRING_OOM 0x01 /* Out of memory */ |
| 203260 | +#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */ |
| 203261 | +#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */ |
| 203262 | + |
| 203263 | +/* The "subtype" set for text JSON values passed through using |
| 203264 | +** sqlite3_result_subtype() and sqlite3_value_subtype(). |
| 203265 | +*/ |
| 202766 | 203266 | #define JSON_SUBTYPE 74 /* Ascii for "J" */ |
| 202767 | 203267 | |
| 202768 | 203268 | /* |
| 202769 | | -** Names of the various JSON types: |
| 202770 | | -*/ |
| 202771 | | -static const char * const jsonType[] = { |
| 202772 | | - "subst", |
| 202773 | | - "null", "true", "false", "integer", "real", "text", "array", "object" |
| 202774 | | -}; |
| 202775 | | - |
| 202776 | | -/* Bit values for the JsonNode.jnFlag field |
| 202777 | | -*/ |
| 202778 | | -#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ |
| 202779 | | -#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ |
| 202780 | | -#define JNODE_REMOVE 0x04 /* Do not output */ |
| 202781 | | -#define JNODE_REPLACE 0x08 /* Target of a JSON_SUBST node */ |
| 202782 | | -#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ |
| 202783 | | -#define JNODE_LABEL 0x20 /* Is a label of an object */ |
| 202784 | | -#define JNODE_JSON5 0x40 /* Node contains JSON5 enhancements */ |
| 202785 | | - |
| 202786 | | - |
| 202787 | | -/* A single node of parsed JSON. An array of these nodes describes |
| 202788 | | -** a parse of JSON + edits. |
| 202789 | | -** |
| 202790 | | -** Use the json_parse() SQL function (available when compiled with |
| 202791 | | -** -DSQLITE_DEBUG) to see a dump of complete JsonParse objects, including |
| 202792 | | -** a complete listing and decoding of the array of JsonNodes. |
| 202793 | | -*/ |
| 202794 | | -struct JsonNode { |
| 202795 | | - u8 eType; /* One of the JSON_ type values */ |
| 202796 | | - u8 jnFlags; /* JNODE flags */ |
| 202797 | | - u8 eU; /* Which union element to use */ |
| 202798 | | - u32 n; /* Bytes of content for INT, REAL or STRING |
| 202799 | | - ** Number of sub-nodes for ARRAY and OBJECT |
| 202800 | | - ** Node that SUBST applies to */ |
| 202801 | | - union { |
| 202802 | | - const char *zJContent; /* 1: Content for INT, REAL, and STRING */ |
| 202803 | | - u32 iAppend; /* 2: More terms for ARRAY and OBJECT */ |
| 202804 | | - u32 iKey; /* 3: Key for ARRAY objects in json_tree() */ |
| 202805 | | - u32 iPrev; /* 4: Previous SUBST node, or 0 */ |
| 202806 | | - } u; |
| 202807 | | -}; |
| 202808 | | - |
| 202809 | | - |
| 202810 | | -/* A parsed and possibly edited JSON string. Lifecycle: |
| 202811 | | -** |
| 202812 | | -** 1. JSON comes in and is parsed into an array aNode[]. The original |
| 202813 | | -** JSON text is stored in zJson. |
| 202814 | | -** |
| 202815 | | -** 2. Zero or more changes are made (via json_remove() or json_replace() |
| 202816 | | -** or similar) to the aNode[] array. |
| 202817 | | -** |
| 202818 | | -** 3. A new, edited and mimified JSON string is generated from aNode |
| 202819 | | -** and stored in zAlt. The JsonParse object always owns zAlt. |
| 202820 | | -** |
| 202821 | | -** Step 1 always happens. Step 2 and 3 may or may not happen, depending |
| 202822 | | -** on the operation. |
| 202823 | | -** |
| 202824 | | -** aNode[].u.zJContent entries typically point into zJson. Hence zJson |
| 202825 | | -** must remain valid for the lifespan of the parse. For edits, |
| 202826 | | -** aNode[].u.zJContent might point to malloced space other than zJson. |
| 202827 | | -** Entries in pClup are responsible for freeing that extra malloced space. |
| 202828 | | -** |
| 202829 | | -** When walking the parse tree in aNode[], edits are ignored if useMod is |
| 202830 | | -** false. |
| 203269 | +** Bit values for the flags passed into various SQL function implementations |
| 203270 | +** via the sqlite3_user_data() value. |
| 203271 | +*/ |
| 203272 | +#define JSON_JSON 0x01 /* Result is always JSON */ |
| 203273 | +#define JSON_SQL 0x02 /* Result is always SQL */ |
| 203274 | +#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ |
| 203275 | +#define JSON_ISSET 0x04 /* json_set(), not json_insert() */ |
| 203276 | +#define JSON_BLOB 0x08 /* Use the BLOB output format */ |
| 203277 | + |
| 203278 | + |
| 203279 | +/* A parsed JSON value. Lifecycle: |
| 203280 | +** |
| 203281 | +** 1. JSON comes in and is parsed into a JSONB value in aBlob. The |
| 203282 | +** original text is stored in zJson. This step is skipped if the |
| 203283 | +** input is JSONB instead of text JSON. |
| 203284 | +** |
| 203285 | +** 2. The aBlob[] array is searched using the JSON path notation, if needed. |
| 203286 | +** |
| 203287 | +** 3. Zero or more changes are made to aBlob[] (via json_remove() or |
| 203288 | +** json_replace() or json_patch() or similar). |
| 203289 | +** |
| 203290 | +** 4. New JSON text is generated from the aBlob[] for output. This step |
| 203291 | +** is skipped the function is one of the jsonb_* functions that returns |
| 203292 | +** JSONB instead of text JSON. |
| 202831 | 203293 | */ |
| 202832 | 203294 | struct JsonParse { |
| 202833 | | - u32 nNode; /* Number of slots of aNode[] used */ |
| 202834 | | - u32 nAlloc; /* Number of slots of aNode[] allocated */ |
| 202835 | | - JsonNode *aNode; /* Array of nodes containing the parse */ |
| 202836 | | - char *zJson; /* Original JSON string (before edits) */ |
| 202837 | | - char *zAlt; /* Revised and/or mimified JSON */ |
| 202838 | | - u32 *aUp; /* Index of parent of each node */ |
| 202839 | | - JsonCleanup *pClup;/* Cleanup operations prior to freeing this object */ |
| 203295 | + u8 *aBlob; /* JSONB representation of JSON value */ |
| 203296 | + u32 nBlob; /* Bytes of aBlob[] actually used */ |
| 203297 | + u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */ |
| 203298 | + char *zJson; /* Json text used for parsing */ |
| 203299 | + int nJson; /* Length of the zJson string in bytes */ |
| 202840 | 203300 | u16 iDepth; /* Nesting depth */ |
| 202841 | 203301 | u8 nErr; /* Number of errors seen */ |
| 202842 | 203302 | u8 oom; /* Set to true if out of memory */ |
| 202843 | 203303 | u8 bJsonIsRCStr; /* True if zJson is an RCStr */ |
| 202844 | 203304 | u8 hasNonstd; /* True if input uses non-standard features like JSON5 */ |
| 202845 | | - u8 useMod; /* Actually use the edits contain inside aNode */ |
| 202846 | | - u8 hasMod; /* aNode contains edits from the original zJson */ |
| 203305 | + u8 bReadOnly; /* Do not modify. */ |
| 202847 | 203306 | u32 nJPRef; /* Number of references to this object */ |
| 202848 | | - int nJson; /* Length of the zJson string in bytes */ |
| 202849 | | - int nAlt; /* Length of alternative JSON string zAlt, in bytes */ |
| 202850 | 203307 | u32 iErr; /* Error location in zJson[] */ |
| 202851 | | - u32 iSubst; /* Last JSON_SUBST entry in aNode[] */ |
| 202852 | | - u32 iHold; /* Age of this entry in the cache for LRU replacement */ |
| 203308 | + /* Search and edit information. See jsonLookupStep() */ |
| 203309 | + u8 eEdit; /* Edit operation to apply */ |
| 203310 | + int delta; /* Size change due to the edit */ |
| 203311 | + u32 nIns; /* Number of bytes to insert */ |
| 203312 | + u32 iLabel; /* Location of label if search landed on an object value */ |
| 203313 | + u8 *aIns; /* Content to be inserted */ |
| 202853 | 203314 | }; |
| 202854 | 203315 | |
| 203316 | +/* Allowed values for JsonParse.eEdit */ |
| 203317 | +#define JEDIT_DEL 1 /* Delete if exists */ |
| 203318 | +#define JEDIT_REPL 2 /* Overwrite if exists */ |
| 203319 | +#define JEDIT_INS 3 /* Insert if not exists */ |
| 203320 | +#define JEDIT_SET 4 /* Insert or overwrite */ |
| 203321 | + |
| 202855 | 203322 | /* |
| 202856 | 203323 | ** Maximum nesting depth of JSON for this implementation. |
| 202857 | 203324 | ** |
| 202858 | 203325 | ** This limit is needed to avoid a stack overflow in the recursive |
| 202859 | 203326 | ** descent parser. A depth of 1000 is far deeper than any sane JSON |
| 202860 | 203327 | ** should go. Historical note: This limit was 2000 prior to version 3.42.0 |
| 202861 | 203328 | */ |
| 202862 | | -#define JSON_MAX_DEPTH 1000 |
| 203329 | +#ifndef SQLITE_JSON_MAX_DEPTH |
| 203330 | +# define JSON_MAX_DEPTH 1000 |
| 203331 | +#else |
| 203332 | +# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH |
| 203333 | +#endif |
| 203334 | + |
| 203335 | +/* |
| 203336 | +** Allowed values for the flgs argument to jsonParseFuncArg(); |
| 203337 | +*/ |
| 203338 | +#define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */ |
| 203339 | +#define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */ |
| 203340 | + |
| 203341 | +/************************************************************************** |
| 203342 | +** Forward references |
| 203343 | +**************************************************************************/ |
| 203344 | +static void jsonReturnStringAsBlob(JsonString*); |
| 203345 | +static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); |
| 203346 | +static u32 jsonXlateBlobToText(const JsonParse*,u32,JsonString*); |
| 203347 | +static void jsonReturnParse(sqlite3_context*,JsonParse*); |
| 203348 | +static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); |
| 203349 | +static void jsonParseFree(JsonParse*); |
| 203350 | +static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); |
| 203351 | +static u32 jsonUnescapeOneChar(const char*, u32, u32*); |
| 203352 | + |
| 203353 | +/************************************************************************** |
| 203354 | +** Utility routines for dealing with JsonCache objects |
| 203355 | +**************************************************************************/ |
| 203356 | + |
| 203357 | +/* |
| 203358 | +** Free a JsonCache object. |
| 203359 | +*/ |
| 203360 | +static void jsonCacheDelete(JsonCache *p){ |
| 203361 | + int i; |
| 203362 | + for(i=0; i<p->nUsed; i++){ |
| 203363 | + jsonParseFree(p->a[i]); |
| 203364 | + } |
| 203365 | + sqlite3DbFree(p->db, p); |
| 203366 | +} |
| 203367 | +static void jsonCacheDeleteGeneric(void *p){ |
| 203368 | + jsonCacheDelete((JsonCache*)p); |
| 203369 | +} |
| 203370 | + |
| 203371 | +/* |
| 203372 | +** Insert a new entry into the cache. If the cache is full, expel |
| 203373 | +** the least recently used entry. Return SQLITE_OK on success or a |
| 203374 | +** result code otherwise. |
| 203375 | +** |
| 203376 | +** Cache entries are stored in age order, oldest first. |
| 203377 | +*/ |
| 203378 | +static int jsonCacheInsert( |
| 203379 | + sqlite3_context *ctx, /* The SQL statement context holding the cache */ |
| 203380 | + JsonParse *pParse /* The parse object to be added to the cache */ |
| 203381 | +){ |
| 203382 | + JsonCache *p; |
| 203383 | + |
| 203384 | + assert( pParse->zJson!=0 ); |
| 203385 | + assert( pParse->bJsonIsRCStr ); |
| 203386 | + p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); |
| 203387 | + if( p==0 ){ |
| 203388 | + sqlite3 *db = sqlite3_context_db_handle(ctx); |
| 203389 | + p = sqlite3DbMallocZero(db, sizeof(*p)); |
| 203390 | + if( p==0 ) return SQLITE_NOMEM; |
| 203391 | + p->db = db; |
| 203392 | + sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric); |
| 203393 | + p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); |
| 203394 | + if( p==0 ) return SQLITE_NOMEM; |
| 203395 | + } |
| 203396 | + if( p->nUsed >= JSON_CACHE_SIZE ){ |
| 203397 | + jsonParseFree(p->a[0]); |
| 203398 | + memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0])); |
| 203399 | + p->nUsed = JSON_CACHE_SIZE-1; |
| 203400 | + } |
| 203401 | + assert( pParse->nBlobAlloc>0 ); |
| 203402 | + pParse->eEdit = 0; |
| 203403 | + pParse->nJPRef++; |
| 203404 | + pParse->bReadOnly = 1; |
| 203405 | + p->a[p->nUsed] = pParse; |
| 203406 | + p->nUsed++; |
| 203407 | + return SQLITE_OK; |
| 203408 | +} |
| 203409 | + |
| 203410 | +/* |
| 203411 | +** Search for a cached translation the json text supplied by pArg. Return |
| 203412 | +** the JsonParse object if found. Return NULL if not found. |
| 203413 | +** |
| 203414 | +** When a match if found, the matching entry is moved to become the |
| 203415 | +** most-recently used entry if it isn't so already. |
| 203416 | +** |
| 203417 | +** The JsonParse object returned still belongs to the Cache and might |
| 203418 | +** be deleted at any moment. If the caller whants the JsonParse to |
| 203419 | +** linger, it needs to increment the nPJRef reference counter. |
| 203420 | +*/ |
| 203421 | +static JsonParse *jsonCacheSearch( |
| 203422 | + sqlite3_context *ctx, /* The SQL statement context holding the cache */ |
| 203423 | + sqlite3_value *pArg /* Function argument containing SQL text */ |
| 203424 | +){ |
| 203425 | + JsonCache *p; |
| 203426 | + int i; |
| 203427 | + const char *zJson; |
| 203428 | + int nJson; |
| 203429 | + |
| 203430 | + if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){ |
| 203431 | + return 0; |
| 203432 | + } |
| 203433 | + zJson = (const char*)sqlite3_value_text(pArg); |
| 203434 | + if( zJson==0 ) return 0; |
| 203435 | + nJson = sqlite3_value_bytes(pArg); |
| 203436 | + |
| 203437 | + p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID); |
| 203438 | + if( p==0 ){ |
| 203439 | + return 0; |
| 203440 | + } |
| 203441 | + for(i=0; i<p->nUsed; i++){ |
| 203442 | + if( p->a[i]->zJson==zJson ) break; |
| 203443 | + } |
| 203444 | + if( i>=p->nUsed ){ |
| 203445 | + for(i=0; i<p->nUsed; i++){ |
| 203446 | + if( p->a[i]->nJson!=nJson ) continue; |
| 203447 | + if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break; |
| 203448 | + } |
| 203449 | + } |
| 203450 | + if( i<p->nUsed ){ |
| 203451 | + if( i<p->nUsed-1 ){ |
| 203452 | + /* Make the matching entry the most recently used entry */ |
| 203453 | + JsonParse *tmp = p->a[i]; |
| 203454 | + memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp)); |
| 203455 | + p->a[p->nUsed-1] = tmp; |
| 203456 | + i = p->nUsed - 1; |
| 203457 | + } |
| 203458 | + return p->a[i]; |
| 203459 | + }else{ |
| 203460 | + return 0; |
| 203461 | + } |
| 203462 | +} |
| 202863 | 203463 | |
| 202864 | 203464 | /************************************************************************** |
| 202865 | 203465 | ** Utility routines for dealing with JsonString objects |
| 202866 | 203466 | **************************************************************************/ |
| 202867 | 203467 | |
| 202868 | | -/* Set the JsonString object to an empty string |
| 203468 | +/* Turn uninitialized bulk memory into a valid JsonString object |
| 203469 | +** holding a zero-length string. |
| 202869 | 203470 | */ |
| 202870 | | -static void jsonZero(JsonString *p){ |
| 203471 | +static void jsonStringZero(JsonString *p){ |
| 202871 | 203472 | p->zBuf = p->zSpace; |
| 202872 | 203473 | p->nAlloc = sizeof(p->zSpace); |
| 202873 | 203474 | p->nUsed = 0; |
| 202874 | 203475 | p->bStatic = 1; |
| 202875 | 203476 | } |
| 202876 | 203477 | |
| 202877 | 203478 | /* Initialize the JsonString object |
| 202878 | 203479 | */ |
| 202879 | | -static void jsonInit(JsonString *p, sqlite3_context *pCtx){ |
| 203480 | +static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){ |
| 202880 | 203481 | p->pCtx = pCtx; |
| 202881 | | - p->bErr = 0; |
| 202882 | | - jsonZero(p); |
| 203482 | + p->eErr = 0; |
| 203483 | + jsonStringZero(p); |
| 202883 | 203484 | } |
| 202884 | 203485 | |
| 202885 | 203486 | /* Free all allocated memory and reset the JsonString object back to its |
| 202886 | 203487 | ** initial state. |
| 202887 | 203488 | */ |
| 202888 | | -static void jsonReset(JsonString *p){ |
| 203489 | +static void jsonStringReset(JsonString *p){ |
| 202889 | 203490 | if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf); |
| 202890 | | - jsonZero(p); |
| 203491 | + jsonStringZero(p); |
| 202891 | 203492 | } |
| 202892 | 203493 | |
| 202893 | 203494 | /* Report an out-of-memory (OOM) condition |
| 202894 | 203495 | */ |
| 202895 | | -static void jsonOom(JsonString *p){ |
| 202896 | | - p->bErr = 1; |
| 202897 | | - sqlite3_result_error_nomem(p->pCtx); |
| 202898 | | - jsonReset(p); |
| 203496 | +static void jsonStringOom(JsonString *p){ |
| 203497 | + p->eErr |= JSTRING_OOM; |
| 203498 | + if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx); |
| 203499 | + jsonStringReset(p); |
| 202899 | 203500 | } |
| 202900 | 203501 | |
| 202901 | 203502 | /* Enlarge pJson->zBuf so that it can hold at least N more bytes. |
| 202902 | 203503 | ** Return zero on success. Return non-zero on an OOM error |
| 202903 | 203504 | */ |
| 202904 | | -static int jsonGrow(JsonString *p, u32 N){ |
| 203505 | +static int jsonStringGrow(JsonString *p, u32 N){ |
| 202905 | 203506 | u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10; |
| 202906 | 203507 | char *zNew; |
| 202907 | 203508 | if( p->bStatic ){ |
| 202908 | | - if( p->bErr ) return 1; |
| 203509 | + if( p->eErr ) return 1; |
| 202909 | 203510 | zNew = sqlite3RCStrNew(nTotal); |
| 202910 | 203511 | if( zNew==0 ){ |
| 202911 | | - jsonOom(p); |
| 203512 | + jsonStringOom(p); |
| 202912 | 203513 | return SQLITE_NOMEM; |
| 202913 | 203514 | } |
| 202914 | 203515 | memcpy(zNew, p->zBuf, (size_t)p->nUsed); |
| 202915 | 203516 | p->zBuf = zNew; |
| 202916 | 203517 | p->bStatic = 0; |
| 202917 | 203518 | }else{ |
| 202918 | 203519 | p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal); |
| 202919 | 203520 | if( p->zBuf==0 ){ |
| 202920 | | - p->bErr = 1; |
| 202921 | | - jsonZero(p); |
| 203521 | + p->eErr |= JSTRING_OOM; |
| 203522 | + jsonStringZero(p); |
| 202922 | 203523 | return SQLITE_NOMEM; |
| 202923 | 203524 | } |
| 202924 | 203525 | } |
| 202925 | 203526 | p->nAlloc = nTotal; |
| 202926 | 203527 | return SQLITE_OK; |
| 202927 | 203528 | } |
| 202928 | 203529 | |
| 202929 | 203530 | /* Append N bytes from zIn onto the end of the JsonString string. |
| 202930 | 203531 | */ |
| 202931 | | -static SQLITE_NOINLINE void jsonAppendExpand( |
| 203532 | +static SQLITE_NOINLINE void jsonStringExpandAndAppend( |
| 202932 | 203533 | JsonString *p, |
| 202933 | 203534 | const char *zIn, |
| 202934 | 203535 | u32 N |
| 202935 | 203536 | ){ |
| 202936 | 203537 | assert( N>0 ); |
| 202937 | | - if( jsonGrow(p,N) ) return; |
| 203538 | + if( jsonStringGrow(p,N) ) return; |
| 202938 | 203539 | memcpy(p->zBuf+p->nUsed, zIn, N); |
| 202939 | 203540 | p->nUsed += N; |
| 202940 | 203541 | } |
| 202941 | 203542 | static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ |
| 202942 | 203543 | if( N==0 ) return; |
| 202943 | 203544 | if( N+p->nUsed >= p->nAlloc ){ |
| 202944 | | - jsonAppendExpand(p,zIn,N); |
| 203545 | + jsonStringExpandAndAppend(p,zIn,N); |
| 202945 | 203546 | }else{ |
| 202946 | 203547 | memcpy(p->zBuf+p->nUsed, zIn, N); |
| 202947 | 203548 | p->nUsed += N; |
| 202948 | 203549 | } |
| 202949 | 203550 | } |
| 202950 | 203551 | static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){ |
| 202951 | 203552 | assert( N>0 ); |
| 202952 | 203553 | if( N+p->nUsed >= p->nAlloc ){ |
| 202953 | | - jsonAppendExpand(p,zIn,N); |
| 203554 | + jsonStringExpandAndAppend(p,zIn,N); |
| 202954 | 203555 | }else{ |
| 202955 | 203556 | memcpy(p->zBuf+p->nUsed, zIn, N); |
| 202956 | 203557 | p->nUsed += N; |
| 202957 | 203558 | } |
| 202958 | 203559 | } |
| | @@ -202960,21 +203561,21 @@ |
| 202960 | 203561 | |
| 202961 | 203562 | /* Append formatted text (not to exceed N bytes) to the JsonString. |
| 202962 | 203563 | */ |
| 202963 | 203564 | static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ |
| 202964 | 203565 | va_list ap; |
| 202965 | | - if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; |
| 203566 | + if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return; |
| 202966 | 203567 | va_start(ap, zFormat); |
| 202967 | 203568 | sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); |
| 202968 | 203569 | va_end(ap); |
| 202969 | 203570 | p->nUsed += (int)strlen(p->zBuf+p->nUsed); |
| 202970 | 203571 | } |
| 202971 | 203572 | |
| 202972 | 203573 | /* Append a single character |
| 202973 | 203574 | */ |
| 202974 | 203575 | static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){ |
| 202975 | | - if( jsonGrow(p,1) ) return; |
| 203576 | + if( jsonStringGrow(p,1) ) return; |
| 202976 | 203577 | p->zBuf[p->nUsed++] = c; |
| 202977 | 203578 | } |
| 202978 | 203579 | static void jsonAppendChar(JsonString *p, char c){ |
| 202979 | 203580 | if( p->nUsed>=p->nAlloc ){ |
| 202980 | 203581 | jsonAppendCharExpand(p,c); |
| | @@ -202981,27 +203582,20 @@ |
| 202981 | 203582 | }else{ |
| 202982 | 203583 | p->zBuf[p->nUsed++] = c; |
| 202983 | 203584 | } |
| 202984 | 203585 | } |
| 202985 | 203586 | |
| 202986 | | -/* Try to force the string to be a zero-terminated RCStr string. |
| 203587 | +/* Make sure there is a zero terminator on p->zBuf[] |
| 202987 | 203588 | ** |
| 202988 | 203589 | ** Return true on success. Return false if an OOM prevents this |
| 202989 | 203590 | ** from happening. |
| 202990 | 203591 | */ |
| 202991 | | -static int jsonForceRCStr(JsonString *p){ |
| 202992 | | - jsonAppendChar(p, 0); |
| 202993 | | - if( p->bErr ) return 0; |
| 202994 | | - p->nUsed--; |
| 202995 | | - if( p->bStatic==0 ) return 1; |
| 202996 | | - p->nAlloc = 0; |
| 202997 | | - p->nUsed++; |
| 202998 | | - jsonGrow(p, p->nUsed); |
| 202999 | | - p->nUsed--; |
| 203000 | | - return p->bStatic==0; |
| 203001 | | -} |
| 203002 | | - |
| 203592 | +static int jsonStringTerminate(JsonString *p){ |
| 203593 | + jsonAppendChar(p, 0); |
| 203594 | + p->nUsed--; |
| 203595 | + return p->eErr==0; |
| 203596 | +} |
| 203003 | 203597 | |
| 203004 | 203598 | /* Append a comma separator to the output buffer, if the previous |
| 203005 | 203599 | ** character is not '[' or '{'. |
| 203006 | 203600 | */ |
| 203007 | 203601 | static void jsonAppendSeparator(JsonString *p){ |
| | @@ -203011,25 +203605,45 @@ |
| 203011 | 203605 | if( c=='[' || c=='{' ) return; |
| 203012 | 203606 | jsonAppendChar(p, ','); |
| 203013 | 203607 | } |
| 203014 | 203608 | |
| 203015 | 203609 | /* Append the N-byte string in zIn to the end of the JsonString string |
| 203016 | | -** under construction. Enclose the string in "..." and escape |
| 203017 | | -** any double-quotes or backslash characters contained within the |
| 203610 | +** under construction. Enclose the string in double-quotes ("...") and |
| 203611 | +** escape any double-quotes or backslash characters contained within the |
| 203018 | 203612 | ** string. |
| 203613 | +** |
| 203614 | +** This routine is a high-runner. There is a measurable performance |
| 203615 | +** increase associated with unwinding the jsonIsOk[] loop. |
| 203019 | 203616 | */ |
| 203020 | 203617 | static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ |
| 203021 | | - u32 i; |
| 203022 | | - if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; |
| 203618 | + u32 k; |
| 203619 | + u8 c; |
| 203620 | + const u8 *z = (const u8*)zIn; |
| 203621 | + if( z==0 ) return; |
| 203622 | + if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return; |
| 203023 | 203623 | p->zBuf[p->nUsed++] = '"'; |
| 203024 | | - for(i=0; i<N; i++){ |
| 203025 | | - unsigned char c = ((unsigned const char*)zIn)[i]; |
| 203026 | | - if( jsonIsOk[c] ){ |
| 203027 | | - p->zBuf[p->nUsed++] = c; |
| 203028 | | - }else if( c=='"' || c=='\\' ){ |
| 203624 | + while( 1 /*exit-by-break*/ ){ |
| 203625 | + k = 0; |
| 203626 | + while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; } /* <--, */ |
| 203627 | + while( k<N && jsonIsOk[z[k]] ){ k++; } /* <-- loop unwound for speed */ |
| 203628 | + if( k>=N ){ |
| 203629 | + if( k>0 ){ |
| 203630 | + memcpy(&p->zBuf[p->nUsed], z, k); |
| 203631 | + p->nUsed += k; |
| 203632 | + } |
| 203633 | + break; |
| 203634 | + } |
| 203635 | + if( k>0 ){ |
| 203636 | + memcpy(&p->zBuf[p->nUsed], z, k); |
| 203637 | + p->nUsed += k; |
| 203638 | + z += k; |
| 203639 | + N -= k; |
| 203640 | + } |
| 203641 | + c = z[0]; |
| 203642 | + if( c=='"' || c=='\\' ){ |
| 203029 | 203643 | json_simple_escape: |
| 203030 | | - if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; |
| 203644 | + if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return; |
| 203031 | 203645 | p->zBuf[p->nUsed++] = '\\'; |
| 203032 | 203646 | p->zBuf[p->nUsed++] = c; |
| 203033 | 203647 | }else if( c=='\'' ){ |
| 203034 | 203648 | p->zBuf[p->nUsed++] = c; |
| 203035 | 203649 | }else{ |
| | @@ -203046,158 +203660,30 @@ |
| 203046 | 203660 | assert( c>=0 && c<sizeof(aSpecial) ); |
| 203047 | 203661 | if( aSpecial[c] ){ |
| 203048 | 203662 | c = aSpecial[c]; |
| 203049 | 203663 | goto json_simple_escape; |
| 203050 | 203664 | } |
| 203051 | | - if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; |
| 203665 | + if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return; |
| 203052 | 203666 | p->zBuf[p->nUsed++] = '\\'; |
| 203053 | 203667 | p->zBuf[p->nUsed++] = 'u'; |
| 203054 | 203668 | p->zBuf[p->nUsed++] = '0'; |
| 203055 | 203669 | p->zBuf[p->nUsed++] = '0'; |
| 203056 | 203670 | p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4]; |
| 203057 | 203671 | p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf]; |
| 203058 | 203672 | } |
| 203673 | + z++; |
| 203674 | + N--; |
| 203059 | 203675 | } |
| 203060 | 203676 | p->zBuf[p->nUsed++] = '"'; |
| 203061 | 203677 | assert( p->nUsed<p->nAlloc ); |
| 203062 | 203678 | } |
| 203063 | 203679 | |
| 203064 | 203680 | /* |
| 203065 | | -** The zIn[0..N] string is a JSON5 string literal. Append to p a translation |
| 203066 | | -** of the string literal that standard JSON and that omits all JSON5 |
| 203067 | | -** features. |
| 203068 | | -*/ |
| 203069 | | -static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){ |
| 203070 | | - u32 i; |
| 203071 | | - jsonAppendChar(p, '"'); |
| 203072 | | - zIn++; |
| 203073 | | - N -= 2; |
| 203074 | | - while( N>0 ){ |
| 203075 | | - for(i=0; i<N && zIn[i]!='\\' && zIn[i]!='"'; i++){} |
| 203076 | | - if( i>0 ){ |
| 203077 | | - jsonAppendRawNZ(p, zIn, i); |
| 203078 | | - zIn += i; |
| 203079 | | - N -= i; |
| 203080 | | - if( N==0 ) break; |
| 203081 | | - } |
| 203082 | | - if( zIn[0]=='"' ){ |
| 203083 | | - jsonAppendRawNZ(p, "\\\"", 2); |
| 203084 | | - zIn++; |
| 203085 | | - N--; |
| 203086 | | - continue; |
| 203087 | | - } |
| 203088 | | - assert( zIn[0]=='\\' ); |
| 203089 | | - switch( (u8)zIn[1] ){ |
| 203090 | | - case '\'': |
| 203091 | | - jsonAppendChar(p, '\''); |
| 203092 | | - break; |
| 203093 | | - case 'v': |
| 203094 | | - jsonAppendRawNZ(p, "\\u0009", 6); |
| 203095 | | - break; |
| 203096 | | - case 'x': |
| 203097 | | - jsonAppendRawNZ(p, "\\u00", 4); |
| 203098 | | - jsonAppendRawNZ(p, &zIn[2], 2); |
| 203099 | | - zIn += 2; |
| 203100 | | - N -= 2; |
| 203101 | | - break; |
| 203102 | | - case '0': |
| 203103 | | - jsonAppendRawNZ(p, "\\u0000", 6); |
| 203104 | | - break; |
| 203105 | | - case '\r': |
| 203106 | | - if( zIn[2]=='\n' ){ |
| 203107 | | - zIn++; |
| 203108 | | - N--; |
| 203109 | | - } |
| 203110 | | - break; |
| 203111 | | - case '\n': |
| 203112 | | - break; |
| 203113 | | - case 0xe2: |
| 203114 | | - assert( N>=4 ); |
| 203115 | | - assert( 0x80==(u8)zIn[2] ); |
| 203116 | | - assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] ); |
| 203117 | | - zIn += 2; |
| 203118 | | - N -= 2; |
| 203119 | | - break; |
| 203120 | | - default: |
| 203121 | | - jsonAppendRawNZ(p, zIn, 2); |
| 203122 | | - break; |
| 203123 | | - } |
| 203124 | | - zIn += 2; |
| 203125 | | - N -= 2; |
| 203126 | | - } |
| 203127 | | - jsonAppendChar(p, '"'); |
| 203128 | | -} |
| 203129 | | - |
| 203130 | | -/* |
| 203131 | | -** The zIn[0..N] string is a JSON5 integer literal. Append to p a translation |
| 203132 | | -** of the string literal that standard JSON and that omits all JSON5 |
| 203133 | | -** features. |
| 203134 | | -*/ |
| 203135 | | -static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){ |
| 203136 | | - if( zIn[0]=='+' ){ |
| 203137 | | - zIn++; |
| 203138 | | - N--; |
| 203139 | | - }else if( zIn[0]=='-' ){ |
| 203140 | | - jsonAppendChar(p, '-'); |
| 203141 | | - zIn++; |
| 203142 | | - N--; |
| 203143 | | - } |
| 203144 | | - if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){ |
| 203145 | | - sqlite3_int64 i = 0; |
| 203146 | | - int rc = sqlite3DecOrHexToI64(zIn, &i); |
| 203147 | | - if( rc<=1 ){ |
| 203148 | | - jsonPrintf(100,p,"%lld",i); |
| 203149 | | - }else{ |
| 203150 | | - assert( rc==2 ); |
| 203151 | | - jsonAppendRawNZ(p, "9.0e999", 7); |
| 203152 | | - } |
| 203153 | | - return; |
| 203154 | | - } |
| 203155 | | - assert( N>0 ); |
| 203156 | | - jsonAppendRawNZ(p, zIn, N); |
| 203157 | | -} |
| 203158 | | - |
| 203159 | | -/* |
| 203160 | | -** The zIn[0..N] string is a JSON5 real literal. Append to p a translation |
| 203161 | | -** of the string literal that standard JSON and that omits all JSON5 |
| 203162 | | -** features. |
| 203163 | | -*/ |
| 203164 | | -static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){ |
| 203165 | | - u32 i; |
| 203166 | | - if( zIn[0]=='+' ){ |
| 203167 | | - zIn++; |
| 203168 | | - N--; |
| 203169 | | - }else if( zIn[0]=='-' ){ |
| 203170 | | - jsonAppendChar(p, '-'); |
| 203171 | | - zIn++; |
| 203172 | | - N--; |
| 203173 | | - } |
| 203174 | | - if( zIn[0]=='.' ){ |
| 203175 | | - jsonAppendChar(p, '0'); |
| 203176 | | - } |
| 203177 | | - for(i=0; i<N; i++){ |
| 203178 | | - if( zIn[i]=='.' && (i+1==N || !sqlite3Isdigit(zIn[i+1])) ){ |
| 203179 | | - i++; |
| 203180 | | - jsonAppendRaw(p, zIn, i); |
| 203181 | | - zIn += i; |
| 203182 | | - N -= i; |
| 203183 | | - jsonAppendChar(p, '0'); |
| 203184 | | - break; |
| 203185 | | - } |
| 203186 | | - } |
| 203187 | | - if( N>0 ){ |
| 203188 | | - jsonAppendRawNZ(p, zIn, N); |
| 203189 | | - } |
| 203190 | | -} |
| 203191 | | - |
| 203192 | | - |
| 203193 | | - |
| 203194 | | -/* |
| 203195 | | -** Append a function parameter value to the JSON string under |
| 203196 | | -** construction. |
| 203197 | | -*/ |
| 203198 | | -static void jsonAppendValue( |
| 203681 | +** Append an sqlite3_value (such as a function parameter) to the JSON |
| 203682 | +** string under construction in p. |
| 203683 | +*/ |
| 203684 | +static void jsonAppendSqlValue( |
| 203199 | 203685 | JsonString *p, /* Append to this JSON string */ |
| 203200 | 203686 | sqlite3_value *pValue /* Value to append */ |
| 203201 | 203687 | ){ |
| 203202 | 203688 | switch( sqlite3_value_type(pValue) ){ |
| 203203 | 203689 | case SQLITE_NULL: { |
| | @@ -203223,591 +203709,147 @@ |
| 203223 | 203709 | jsonAppendString(p, z, n); |
| 203224 | 203710 | } |
| 203225 | 203711 | break; |
| 203226 | 203712 | } |
| 203227 | 203713 | default: { |
| 203228 | | - if( p->bErr==0 ){ |
| 203714 | + if( jsonFuncArgMightBeBinary(pValue) ){ |
| 203715 | + JsonParse px; |
| 203716 | + memset(&px, 0, sizeof(px)); |
| 203717 | + px.aBlob = (u8*)sqlite3_value_blob(pValue); |
| 203718 | + px.nBlob = sqlite3_value_bytes(pValue); |
| 203719 | + jsonXlateBlobToText(&px, 0, p); |
| 203720 | + }else if( p->eErr==0 ){ |
| 203229 | 203721 | sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
| 203230 | | - p->bErr = 2; |
| 203231 | | - jsonReset(p); |
| 203722 | + p->eErr = JSTRING_ERR; |
| 203723 | + jsonStringReset(p); |
| 203232 | 203724 | } |
| 203233 | 203725 | break; |
| 203234 | 203726 | } |
| 203235 | 203727 | } |
| 203236 | 203728 | } |
| 203237 | 203729 | |
| 203238 | | - |
| 203239 | | -/* Make the JSON in p the result of the SQL function. |
| 203730 | +/* Make the text in p (which is probably a generated JSON text string) |
| 203731 | +** the result of the SQL function. |
| 203240 | 203732 | ** |
| 203241 | | -** The JSON string is reset. |
| 203733 | +** The JsonString is reset. |
| 203734 | +** |
| 203735 | +** If pParse and ctx are both non-NULL, then the SQL string in p is |
| 203736 | +** loaded into the zJson field of the pParse object as a RCStr and the |
| 203737 | +** pParse is added to the cache. |
| 203242 | 203738 | */ |
| 203243 | | -static void jsonResult(JsonString *p){ |
| 203244 | | - if( p->bErr==0 ){ |
| 203245 | | - if( p->bStatic ){ |
| 203739 | +static void jsonReturnString( |
| 203740 | + JsonString *p, /* String to return */ |
| 203741 | + JsonParse *pParse, /* JSONB source or NULL */ |
| 203742 | + sqlite3_context *ctx /* Where to cache */ |
| 203743 | +){ |
| 203744 | + assert( (pParse!=0)==(ctx!=0) ); |
| 203745 | + assert( ctx==0 || ctx==p->pCtx ); |
| 203746 | + if( p->eErr==0 ){ |
| 203747 | + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx)); |
| 203748 | + if( flags & JSON_BLOB ){ |
| 203749 | + jsonReturnStringAsBlob(p); |
| 203750 | + }else if( p->bStatic ){ |
| 203246 | 203751 | sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, |
| 203247 | 203752 | SQLITE_TRANSIENT, SQLITE_UTF8); |
| 203248 | | - }else if( jsonForceRCStr(p) ){ |
| 203249 | | - sqlite3RCStrRef(p->zBuf); |
| 203250 | | - sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, |
| 203753 | + }else if( jsonStringTerminate(p) ){ |
| 203754 | + if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){ |
| 203755 | + int rc; |
| 203756 | + pParse->zJson = sqlite3RCStrRef(p->zBuf); |
| 203757 | + pParse->nJson = p->nUsed; |
| 203758 | + pParse->bJsonIsRCStr = 1; |
| 203759 | + rc = jsonCacheInsert(ctx, pParse); |
| 203760 | + if( rc==SQLITE_NOMEM ){ |
| 203761 | + sqlite3_result_error_nomem(ctx); |
| 203762 | + jsonStringReset(p); |
| 203763 | + return; |
| 203764 | + } |
| 203765 | + } |
| 203766 | + sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, |
| 203251 | 203767 | sqlite3RCStrUnref, |
| 203252 | 203768 | SQLITE_UTF8); |
| 203769 | + }else{ |
| 203770 | + sqlite3_result_error_nomem(p->pCtx); |
| 203253 | 203771 | } |
| 203254 | | - } |
| 203255 | | - if( p->bErr==1 ){ |
| 203772 | + }else if( p->eErr & JSTRING_OOM ){ |
| 203256 | 203773 | sqlite3_result_error_nomem(p->pCtx); |
| 203774 | + }else if( p->eErr & JSTRING_MALFORMED ){ |
| 203775 | + sqlite3_result_error(p->pCtx, "malformed JSON", -1); |
| 203257 | 203776 | } |
| 203258 | | - jsonReset(p); |
| 203777 | + jsonStringReset(p); |
| 203259 | 203778 | } |
| 203260 | 203779 | |
| 203261 | 203780 | /************************************************************************** |
| 203262 | | -** Utility routines for dealing with JsonNode and JsonParse objects |
| 203781 | +** Utility routines for dealing with JsonParse objects |
| 203263 | 203782 | **************************************************************************/ |
| 203264 | 203783 | |
| 203265 | | -/* |
| 203266 | | -** Return the number of consecutive JsonNode slots need to represent |
| 203267 | | -** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and |
| 203268 | | -** OBJECT types, the number might be larger. |
| 203269 | | -** |
| 203270 | | -** Appended elements are not counted. The value returned is the number |
| 203271 | | -** by which the JsonNode counter should increment in order to go to the |
| 203272 | | -** next peer value. |
| 203273 | | -*/ |
| 203274 | | -static u32 jsonNodeSize(JsonNode *pNode){ |
| 203275 | | - return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; |
| 203276 | | -} |
| 203277 | | - |
| 203278 | 203784 | /* |
| 203279 | 203785 | ** Reclaim all memory allocated by a JsonParse object. But do not |
| 203280 | 203786 | ** delete the JsonParse object itself. |
| 203281 | 203787 | */ |
| 203282 | 203788 | static void jsonParseReset(JsonParse *pParse){ |
| 203283 | | - while( pParse->pClup ){ |
| 203284 | | - JsonCleanup *pTask = pParse->pClup; |
| 203285 | | - pParse->pClup = pTask->pJCNext; |
| 203286 | | - pTask->xOp(pTask->pArg); |
| 203287 | | - sqlite3_free(pTask); |
| 203288 | | - } |
| 203289 | 203789 | assert( pParse->nJPRef<=1 ); |
| 203290 | | - if( pParse->aNode ){ |
| 203291 | | - sqlite3_free(pParse->aNode); |
| 203292 | | - pParse->aNode = 0; |
| 203293 | | - } |
| 203294 | | - pParse->nNode = 0; |
| 203295 | | - pParse->nAlloc = 0; |
| 203296 | | - if( pParse->aUp ){ |
| 203297 | | - sqlite3_free(pParse->aUp); |
| 203298 | | - pParse->aUp = 0; |
| 203299 | | - } |
| 203300 | 203790 | if( pParse->bJsonIsRCStr ){ |
| 203301 | 203791 | sqlite3RCStrUnref(pParse->zJson); |
| 203302 | 203792 | pParse->zJson = 0; |
| 203793 | + pParse->nJson = 0; |
| 203303 | 203794 | pParse->bJsonIsRCStr = 0; |
| 203304 | 203795 | } |
| 203305 | | - if( pParse->zAlt ){ |
| 203306 | | - sqlite3RCStrUnref(pParse->zAlt); |
| 203307 | | - pParse->zAlt = 0; |
| 203796 | + if( pParse->nBlobAlloc ){ |
| 203797 | + sqlite3_free(pParse->aBlob); |
| 203798 | + pParse->aBlob = 0; |
| 203799 | + pParse->nBlob = 0; |
| 203800 | + pParse->nBlobAlloc = 0; |
| 203308 | 203801 | } |
| 203309 | 203802 | } |
| 203310 | 203803 | |
| 203311 | 203804 | /* |
| 203312 | | -** Free a JsonParse object that was obtained from sqlite3_malloc(). |
| 203313 | | -** |
| 203314 | | -** Note that destroying JsonParse might call sqlite3RCStrUnref() to |
| 203315 | | -** destroy the zJson value. The RCStr object might recursively invoke |
| 203316 | | -** JsonParse to destroy this pParse object again. Take care to ensure |
| 203317 | | -** that this recursive destructor sequence terminates harmlessly. |
| 203805 | +** Decrement the reference count on the JsonParse object. When the |
| 203806 | +** count reaches zero, free the object. |
| 203318 | 203807 | */ |
| 203319 | 203808 | static void jsonParseFree(JsonParse *pParse){ |
| 203320 | | - if( pParse->nJPRef>1 ){ |
| 203321 | | - pParse->nJPRef--; |
| 203322 | | - }else{ |
| 203323 | | - jsonParseReset(pParse); |
| 203324 | | - sqlite3_free(pParse); |
| 203325 | | - } |
| 203326 | | -} |
| 203327 | | - |
| 203328 | | -/* |
| 203329 | | -** Add a cleanup task to the JsonParse object. |
| 203330 | | -** |
| 203331 | | -** If an OOM occurs, the cleanup operation happens immediately |
| 203332 | | -** and this function returns SQLITE_NOMEM. |
| 203333 | | -*/ |
| 203334 | | -static int jsonParseAddCleanup( |
| 203335 | | - JsonParse *pParse, /* Add the cleanup task to this parser */ |
| 203336 | | - void(*xOp)(void*), /* The cleanup task */ |
| 203337 | | - void *pArg /* Argument to the cleanup */ |
| 203338 | | -){ |
| 203339 | | - JsonCleanup *pTask = sqlite3_malloc64( sizeof(*pTask) ); |
| 203340 | | - if( pTask==0 ){ |
| 203341 | | - pParse->oom = 1; |
| 203342 | | - xOp(pArg); |
| 203343 | | - return SQLITE_ERROR; |
| 203344 | | - } |
| 203345 | | - pTask->pJCNext = pParse->pClup; |
| 203346 | | - pParse->pClup = pTask; |
| 203347 | | - pTask->xOp = xOp; |
| 203348 | | - pTask->pArg = pArg; |
| 203349 | | - return SQLITE_OK; |
| 203350 | | -} |
| 203351 | | - |
| 203352 | | -/* |
| 203353 | | -** Convert the JsonNode pNode into a pure JSON string and |
| 203354 | | -** append to pOut. Subsubstructure is also included. Return |
| 203355 | | -** the number of JsonNode objects that are encoded. |
| 203356 | | -*/ |
| 203357 | | -static void jsonRenderNode( |
| 203358 | | - JsonParse *pParse, /* the complete parse of the JSON */ |
| 203359 | | - JsonNode *pNode, /* The node to render */ |
| 203360 | | - JsonString *pOut /* Write JSON here */ |
| 203361 | | -){ |
| 203362 | | - assert( pNode!=0 ); |
| 203363 | | - while( (pNode->jnFlags & JNODE_REPLACE)!=0 && pParse->useMod ){ |
| 203364 | | - u32 idx = (u32)(pNode - pParse->aNode); |
| 203365 | | - u32 i = pParse->iSubst; |
| 203366 | | - while( 1 /*exit-by-break*/ ){ |
| 203367 | | - assert( i<pParse->nNode ); |
| 203368 | | - assert( pParse->aNode[i].eType==JSON_SUBST ); |
| 203369 | | - assert( pParse->aNode[i].eU==4 ); |
| 203370 | | - assert( pParse->aNode[i].u.iPrev<i ); |
| 203371 | | - if( pParse->aNode[i].n==idx ){ |
| 203372 | | - pNode = &pParse->aNode[i+1]; |
| 203373 | | - break; |
| 203374 | | - } |
| 203375 | | - i = pParse->aNode[i].u.iPrev; |
| 203376 | | - } |
| 203377 | | - } |
| 203378 | | - switch( pNode->eType ){ |
| 203379 | | - default: { |
| 203380 | | - assert( pNode->eType==JSON_NULL ); |
| 203381 | | - jsonAppendRawNZ(pOut, "null", 4); |
| 203382 | | - break; |
| 203383 | | - } |
| 203384 | | - case JSON_TRUE: { |
| 203385 | | - jsonAppendRawNZ(pOut, "true", 4); |
| 203386 | | - break; |
| 203387 | | - } |
| 203388 | | - case JSON_FALSE: { |
| 203389 | | - jsonAppendRawNZ(pOut, "false", 5); |
| 203390 | | - break; |
| 203391 | | - } |
| 203392 | | - case JSON_STRING: { |
| 203393 | | - assert( pNode->eU==1 ); |
| 203394 | | - if( pNode->jnFlags & JNODE_RAW ){ |
| 203395 | | - if( pNode->jnFlags & JNODE_LABEL ){ |
| 203396 | | - jsonAppendChar(pOut, '"'); |
| 203397 | | - jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); |
| 203398 | | - jsonAppendChar(pOut, '"'); |
| 203399 | | - }else{ |
| 203400 | | - jsonAppendString(pOut, pNode->u.zJContent, pNode->n); |
| 203401 | | - } |
| 203402 | | - }else if( pNode->jnFlags & JNODE_JSON5 ){ |
| 203403 | | - jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n); |
| 203404 | | - }else{ |
| 203405 | | - assert( pNode->n>0 ); |
| 203406 | | - jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); |
| 203407 | | - } |
| 203408 | | - break; |
| 203409 | | - } |
| 203410 | | - case JSON_REAL: { |
| 203411 | | - assert( pNode->eU==1 ); |
| 203412 | | - if( pNode->jnFlags & JNODE_JSON5 ){ |
| 203413 | | - jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n); |
| 203414 | | - }else{ |
| 203415 | | - assert( pNode->n>0 ); |
| 203416 | | - jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); |
| 203417 | | - } |
| 203418 | | - break; |
| 203419 | | - } |
| 203420 | | - case JSON_INT: { |
| 203421 | | - assert( pNode->eU==1 ); |
| 203422 | | - if( pNode->jnFlags & JNODE_JSON5 ){ |
| 203423 | | - jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n); |
| 203424 | | - }else{ |
| 203425 | | - assert( pNode->n>0 ); |
| 203426 | | - jsonAppendRawNZ(pOut, pNode->u.zJContent, pNode->n); |
| 203427 | | - } |
| 203428 | | - break; |
| 203429 | | - } |
| 203430 | | - case JSON_ARRAY: { |
| 203431 | | - u32 j = 1; |
| 203432 | | - jsonAppendChar(pOut, '['); |
| 203433 | | - for(;;){ |
| 203434 | | - while( j<=pNode->n ){ |
| 203435 | | - if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ |
| 203436 | | - jsonAppendSeparator(pOut); |
| 203437 | | - jsonRenderNode(pParse, &pNode[j], pOut); |
| 203438 | | - } |
| 203439 | | - j += jsonNodeSize(&pNode[j]); |
| 203440 | | - } |
| 203441 | | - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; |
| 203442 | | - if( pParse->useMod==0 ) break; |
| 203443 | | - assert( pNode->eU==2 ); |
| 203444 | | - pNode = &pParse->aNode[pNode->u.iAppend]; |
| 203445 | | - j = 1; |
| 203446 | | - } |
| 203447 | | - jsonAppendChar(pOut, ']'); |
| 203448 | | - break; |
| 203449 | | - } |
| 203450 | | - case JSON_OBJECT: { |
| 203451 | | - u32 j = 1; |
| 203452 | | - jsonAppendChar(pOut, '{'); |
| 203453 | | - for(;;){ |
| 203454 | | - while( j<=pNode->n ){ |
| 203455 | | - if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ |
| 203456 | | - jsonAppendSeparator(pOut); |
| 203457 | | - jsonRenderNode(pParse, &pNode[j], pOut); |
| 203458 | | - jsonAppendChar(pOut, ':'); |
| 203459 | | - jsonRenderNode(pParse, &pNode[j+1], pOut); |
| 203460 | | - } |
| 203461 | | - j += 1 + jsonNodeSize(&pNode[j+1]); |
| 203462 | | - } |
| 203463 | | - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; |
| 203464 | | - if( pParse->useMod==0 ) break; |
| 203465 | | - assert( pNode->eU==2 ); |
| 203466 | | - pNode = &pParse->aNode[pNode->u.iAppend]; |
| 203467 | | - j = 1; |
| 203468 | | - } |
| 203469 | | - jsonAppendChar(pOut, '}'); |
| 203470 | | - break; |
| 203471 | | - } |
| 203472 | | - } |
| 203473 | | -} |
| 203474 | | - |
| 203475 | | -/* |
| 203476 | | -** Return a JsonNode and all its descendants as a JSON string. |
| 203477 | | -*/ |
| 203478 | | -static void jsonReturnJson( |
| 203479 | | - JsonParse *pParse, /* The complete JSON */ |
| 203480 | | - JsonNode *pNode, /* Node to return */ |
| 203481 | | - sqlite3_context *pCtx, /* Return value for this function */ |
| 203482 | | - int bGenerateAlt, /* Also store the rendered text in zAlt */ |
| 203483 | | - int omitSubtype /* Do not call sqlite3_result_subtype() */ |
| 203484 | | -){ |
| 203485 | | - JsonString s; |
| 203486 | | - if( pParse->oom ){ |
| 203487 | | - sqlite3_result_error_nomem(pCtx); |
| 203488 | | - return; |
| 203489 | | - } |
| 203490 | | - if( pParse->nErr==0 ){ |
| 203491 | | - jsonInit(&s, pCtx); |
| 203492 | | - jsonRenderNode(pParse, pNode, &s); |
| 203493 | | - if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){ |
| 203494 | | - pParse->zAlt = sqlite3RCStrRef(s.zBuf); |
| 203495 | | - pParse->nAlt = s.nUsed; |
| 203496 | | - } |
| 203497 | | - jsonResult(&s); |
| 203498 | | - if( !omitSubtype ) sqlite3_result_subtype(pCtx, JSON_SUBTYPE); |
| 203499 | | - } |
| 203500 | | -} |
| 203809 | + if( pParse ){ |
| 203810 | + if( pParse->nJPRef>1 ){ |
| 203811 | + pParse->nJPRef--; |
| 203812 | + }else{ |
| 203813 | + jsonParseReset(pParse); |
| 203814 | + sqlite3_free(pParse); |
| 203815 | + } |
| 203816 | + } |
| 203817 | +} |
| 203818 | + |
| 203819 | +/************************************************************************** |
| 203820 | +** Utility routines for the JSON text parser |
| 203821 | +**************************************************************************/ |
| 203501 | 203822 | |
| 203502 | 203823 | /* |
| 203503 | 203824 | ** Translate a single byte of Hex into an integer. |
| 203504 | | -** This routine only works if h really is a valid hexadecimal |
| 203505 | | -** character: 0..9a..fA..F |
| 203825 | +** This routine only gives a correct answer if h really is a valid hexadecimal |
| 203826 | +** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not |
| 203827 | +** assert() if the digit is not hex. |
| 203506 | 203828 | */ |
| 203507 | 203829 | static u8 jsonHexToInt(int h){ |
| 203508 | | - assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); |
| 203830 | +#ifdef SQLITE_ASCII |
| 203831 | + h += 9*(1&(h>>6)); |
| 203832 | +#endif |
| 203509 | 203833 | #ifdef SQLITE_EBCDIC |
| 203510 | 203834 | h += 9*(1&~(h>>4)); |
| 203511 | | -#else |
| 203512 | | - h += 9*(1&(h>>6)); |
| 203513 | 203835 | #endif |
| 203514 | 203836 | return (u8)(h & 0xf); |
| 203515 | 203837 | } |
| 203516 | 203838 | |
| 203517 | 203839 | /* |
| 203518 | 203840 | ** Convert a 4-byte hex string into an integer |
| 203519 | 203841 | */ |
| 203520 | 203842 | static u32 jsonHexToInt4(const char *z){ |
| 203521 | 203843 | u32 v; |
| 203522 | | - assert( sqlite3Isxdigit(z[0]) ); |
| 203523 | | - assert( sqlite3Isxdigit(z[1]) ); |
| 203524 | | - assert( sqlite3Isxdigit(z[2]) ); |
| 203525 | | - assert( sqlite3Isxdigit(z[3]) ); |
| 203526 | 203844 | v = (jsonHexToInt(z[0])<<12) |
| 203527 | 203845 | + (jsonHexToInt(z[1])<<8) |
| 203528 | 203846 | + (jsonHexToInt(z[2])<<4) |
| 203529 | 203847 | + jsonHexToInt(z[3]); |
| 203530 | 203848 | return v; |
| 203531 | 203849 | } |
| 203532 | 203850 | |
| 203533 | | -/* |
| 203534 | | -** Make the JsonNode the return value of the function. |
| 203535 | | -*/ |
| 203536 | | -static void jsonReturn( |
| 203537 | | - JsonParse *pParse, /* Complete JSON parse tree */ |
| 203538 | | - JsonNode *pNode, /* Node to return */ |
| 203539 | | - sqlite3_context *pCtx, /* Return value for this function */ |
| 203540 | | - int omitSubtype /* Do not call sqlite3_result_subtype() */ |
| 203541 | | -){ |
| 203542 | | - switch( pNode->eType ){ |
| 203543 | | - default: { |
| 203544 | | - assert( pNode->eType==JSON_NULL ); |
| 203545 | | - sqlite3_result_null(pCtx); |
| 203546 | | - break; |
| 203547 | | - } |
| 203548 | | - case JSON_TRUE: { |
| 203549 | | - sqlite3_result_int(pCtx, 1); |
| 203550 | | - break; |
| 203551 | | - } |
| 203552 | | - case JSON_FALSE: { |
| 203553 | | - sqlite3_result_int(pCtx, 0); |
| 203554 | | - break; |
| 203555 | | - } |
| 203556 | | - case JSON_INT: { |
| 203557 | | - sqlite3_int64 i = 0; |
| 203558 | | - int rc; |
| 203559 | | - int bNeg = 0; |
| 203560 | | - const char *z; |
| 203561 | | - |
| 203562 | | - assert( pNode->eU==1 ); |
| 203563 | | - z = pNode->u.zJContent; |
| 203564 | | - if( z[0]=='-' ){ z++; bNeg = 1; } |
| 203565 | | - else if( z[0]=='+' ){ z++; } |
| 203566 | | - rc = sqlite3DecOrHexToI64(z, &i); |
| 203567 | | - if( rc<=1 ){ |
| 203568 | | - sqlite3_result_int64(pCtx, bNeg ? -i : i); |
| 203569 | | - }else if( rc==3 && bNeg ){ |
| 203570 | | - sqlite3_result_int64(pCtx, SMALLEST_INT64); |
| 203571 | | - }else{ |
| 203572 | | - goto to_double; |
| 203573 | | - } |
| 203574 | | - break; |
| 203575 | | - } |
| 203576 | | - case JSON_REAL: { |
| 203577 | | - double r; |
| 203578 | | - const char *z; |
| 203579 | | - assert( pNode->eU==1 ); |
| 203580 | | - to_double: |
| 203581 | | - z = pNode->u.zJContent; |
| 203582 | | - sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); |
| 203583 | | - sqlite3_result_double(pCtx, r); |
| 203584 | | - break; |
| 203585 | | - } |
| 203586 | | - case JSON_STRING: { |
| 203587 | | - if( pNode->jnFlags & JNODE_RAW ){ |
| 203588 | | - assert( pNode->eU==1 ); |
| 203589 | | - sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, |
| 203590 | | - SQLITE_TRANSIENT); |
| 203591 | | - }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ |
| 203592 | | - /* JSON formatted without any backslash-escapes */ |
| 203593 | | - assert( pNode->eU==1 ); |
| 203594 | | - sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, |
| 203595 | | - SQLITE_TRANSIENT); |
| 203596 | | - }else{ |
| 203597 | | - /* Translate JSON formatted string into raw text */ |
| 203598 | | - u32 i; |
| 203599 | | - u32 n = pNode->n; |
| 203600 | | - const char *z; |
| 203601 | | - char *zOut; |
| 203602 | | - u32 j; |
| 203603 | | - u32 nOut = n; |
| 203604 | | - assert( pNode->eU==1 ); |
| 203605 | | - z = pNode->u.zJContent; |
| 203606 | | - zOut = sqlite3_malloc( nOut+1 ); |
| 203607 | | - if( zOut==0 ){ |
| 203608 | | - sqlite3_result_error_nomem(pCtx); |
| 203609 | | - break; |
| 203610 | | - } |
| 203611 | | - for(i=1, j=0; i<n-1; i++){ |
| 203612 | | - char c = z[i]; |
| 203613 | | - if( c=='\\' ){ |
| 203614 | | - c = z[++i]; |
| 203615 | | - if( c=='u' ){ |
| 203616 | | - u32 v = jsonHexToInt4(z+i+1); |
| 203617 | | - i += 4; |
| 203618 | | - if( v==0 ) break; |
| 203619 | | - if( v<=0x7f ){ |
| 203620 | | - zOut[j++] = (char)v; |
| 203621 | | - }else if( v<=0x7ff ){ |
| 203622 | | - zOut[j++] = (char)(0xc0 | (v>>6)); |
| 203623 | | - zOut[j++] = 0x80 | (v&0x3f); |
| 203624 | | - }else{ |
| 203625 | | - u32 vlo; |
| 203626 | | - if( (v&0xfc00)==0xd800 |
| 203627 | | - && i<n-6 |
| 203628 | | - && z[i+1]=='\\' |
| 203629 | | - && z[i+2]=='u' |
| 203630 | | - && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00 |
| 203631 | | - ){ |
| 203632 | | - /* We have a surrogate pair */ |
| 203633 | | - v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000; |
| 203634 | | - i += 6; |
| 203635 | | - zOut[j++] = 0xf0 | (v>>18); |
| 203636 | | - zOut[j++] = 0x80 | ((v>>12)&0x3f); |
| 203637 | | - zOut[j++] = 0x80 | ((v>>6)&0x3f); |
| 203638 | | - zOut[j++] = 0x80 | (v&0x3f); |
| 203639 | | - }else{ |
| 203640 | | - zOut[j++] = 0xe0 | (v>>12); |
| 203641 | | - zOut[j++] = 0x80 | ((v>>6)&0x3f); |
| 203642 | | - zOut[j++] = 0x80 | (v&0x3f); |
| 203643 | | - } |
| 203644 | | - } |
| 203645 | | - continue; |
| 203646 | | - }else if( c=='b' ){ |
| 203647 | | - c = '\b'; |
| 203648 | | - }else if( c=='f' ){ |
| 203649 | | - c = '\f'; |
| 203650 | | - }else if( c=='n' ){ |
| 203651 | | - c = '\n'; |
| 203652 | | - }else if( c=='r' ){ |
| 203653 | | - c = '\r'; |
| 203654 | | - }else if( c=='t' ){ |
| 203655 | | - c = '\t'; |
| 203656 | | - }else if( c=='v' ){ |
| 203657 | | - c = '\v'; |
| 203658 | | - }else if( c=='\'' || c=='"' || c=='/' || c=='\\' ){ |
| 203659 | | - /* pass through unchanged */ |
| 203660 | | - }else if( c=='0' ){ |
| 203661 | | - c = 0; |
| 203662 | | - }else if( c=='x' ){ |
| 203663 | | - c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]); |
| 203664 | | - i += 2; |
| 203665 | | - }else if( c=='\r' && z[i+1]=='\n' ){ |
| 203666 | | - i++; |
| 203667 | | - continue; |
| 203668 | | - }else if( 0xe2==(u8)c ){ |
| 203669 | | - assert( 0x80==(u8)z[i+1] ); |
| 203670 | | - assert( 0xa8==(u8)z[i+2] || 0xa9==(u8)z[i+2] ); |
| 203671 | | - i += 2; |
| 203672 | | - continue; |
| 203673 | | - }else{ |
| 203674 | | - continue; |
| 203675 | | - } |
| 203676 | | - } /* end if( c=='\\' ) */ |
| 203677 | | - zOut[j++] = c; |
| 203678 | | - } /* end for() */ |
| 203679 | | - zOut[j] = 0; |
| 203680 | | - sqlite3_result_text(pCtx, zOut, j, sqlite3_free); |
| 203681 | | - } |
| 203682 | | - break; |
| 203683 | | - } |
| 203684 | | - case JSON_ARRAY: |
| 203685 | | - case JSON_OBJECT: { |
| 203686 | | - jsonReturnJson(pParse, pNode, pCtx, 0, omitSubtype); |
| 203687 | | - break; |
| 203688 | | - } |
| 203689 | | - } |
| 203690 | | -} |
| 203691 | | - |
| 203692 | | -/* Forward reference */ |
| 203693 | | -static int jsonParseAddNode(JsonParse*,u32,u32,const char*); |
| 203694 | | - |
| 203695 | | -/* |
| 203696 | | -** A macro to hint to the compiler that a function should not be |
| 203697 | | -** inlined. |
| 203698 | | -*/ |
| 203699 | | -#if defined(__GNUC__) |
| 203700 | | -# define JSON_NOINLINE __attribute__((noinline)) |
| 203701 | | -#elif defined(_MSC_VER) && _MSC_VER>=1310 |
| 203702 | | -# define JSON_NOINLINE __declspec(noinline) |
| 203703 | | -#else |
| 203704 | | -# define JSON_NOINLINE |
| 203705 | | -#endif |
| 203706 | | - |
| 203707 | | - |
| 203708 | | -/* |
| 203709 | | -** Add a single node to pParse->aNode after first expanding the |
| 203710 | | -** size of the aNode array. Return the index of the new node. |
| 203711 | | -** |
| 203712 | | -** If an OOM error occurs, set pParse->oom and return -1. |
| 203713 | | -*/ |
| 203714 | | -static JSON_NOINLINE int jsonParseAddNodeExpand( |
| 203715 | | - JsonParse *pParse, /* Append the node to this object */ |
| 203716 | | - u32 eType, /* Node type */ |
| 203717 | | - u32 n, /* Content size or sub-node count */ |
| 203718 | | - const char *zContent /* Content */ |
| 203719 | | -){ |
| 203720 | | - u32 nNew; |
| 203721 | | - JsonNode *pNew; |
| 203722 | | - assert( pParse->nNode>=pParse->nAlloc ); |
| 203723 | | - if( pParse->oom ) return -1; |
| 203724 | | - nNew = pParse->nAlloc*2 + 10; |
| 203725 | | - pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew); |
| 203726 | | - if( pNew==0 ){ |
| 203727 | | - pParse->oom = 1; |
| 203728 | | - return -1; |
| 203729 | | - } |
| 203730 | | - pParse->nAlloc = sqlite3_msize(pNew)/sizeof(JsonNode); |
| 203731 | | - pParse->aNode = pNew; |
| 203732 | | - assert( pParse->nNode<pParse->nAlloc ); |
| 203733 | | - return jsonParseAddNode(pParse, eType, n, zContent); |
| 203734 | | -} |
| 203735 | | - |
| 203736 | | -/* |
| 203737 | | -** Create a new JsonNode instance based on the arguments and append that |
| 203738 | | -** instance to the JsonParse. Return the index in pParse->aNode[] of the |
| 203739 | | -** new node, or -1 if a memory allocation fails. |
| 203740 | | -*/ |
| 203741 | | -static int jsonParseAddNode( |
| 203742 | | - JsonParse *pParse, /* Append the node to this object */ |
| 203743 | | - u32 eType, /* Node type */ |
| 203744 | | - u32 n, /* Content size or sub-node count */ |
| 203745 | | - const char *zContent /* Content */ |
| 203746 | | -){ |
| 203747 | | - JsonNode *p; |
| 203748 | | - assert( pParse->aNode!=0 || pParse->nNode>=pParse->nAlloc ); |
| 203749 | | - if( pParse->nNode>=pParse->nAlloc ){ |
| 203750 | | - return jsonParseAddNodeExpand(pParse, eType, n, zContent); |
| 203751 | | - } |
| 203752 | | - assert( pParse->aNode!=0 ); |
| 203753 | | - p = &pParse->aNode[pParse->nNode]; |
| 203754 | | - assert( p!=0 ); |
| 203755 | | - p->eType = (u8)(eType & 0xff); |
| 203756 | | - p->jnFlags = (u8)(eType >> 8); |
| 203757 | | - VVA( p->eU = zContent ? 1 : 0 ); |
| 203758 | | - p->n = n; |
| 203759 | | - p->u.zJContent = zContent; |
| 203760 | | - return pParse->nNode++; |
| 203761 | | -} |
| 203762 | | - |
| 203763 | | -/* |
| 203764 | | -** Add an array of new nodes to the current pParse->aNode array. |
| 203765 | | -** Return the index of the first node added. |
| 203766 | | -** |
| 203767 | | -** If an OOM error occurs, set pParse->oom. |
| 203768 | | -*/ |
| 203769 | | -static void jsonParseAddNodeArray( |
| 203770 | | - JsonParse *pParse, /* Append the node to this object */ |
| 203771 | | - JsonNode *aNode, /* Array of nodes to add */ |
| 203772 | | - u32 nNode /* Number of elements in aNew */ |
| 203773 | | -){ |
| 203774 | | - assert( aNode!=0 ); |
| 203775 | | - assert( nNode>=1 ); |
| 203776 | | - if( pParse->nNode + nNode > pParse->nAlloc ){ |
| 203777 | | - u32 nNew = pParse->nNode + nNode; |
| 203778 | | - JsonNode *aNew = sqlite3_realloc64(pParse->aNode, nNew*sizeof(JsonNode)); |
| 203779 | | - if( aNew==0 ){ |
| 203780 | | - pParse->oom = 1; |
| 203781 | | - return; |
| 203782 | | - } |
| 203783 | | - pParse->nAlloc = sqlite3_msize(aNew)/sizeof(JsonNode); |
| 203784 | | - pParse->aNode = aNew; |
| 203785 | | - } |
| 203786 | | - memcpy(&pParse->aNode[pParse->nNode], aNode, nNode*sizeof(JsonNode)); |
| 203787 | | - pParse->nNode += nNode; |
| 203788 | | -} |
| 203789 | | - |
| 203790 | | -/* |
| 203791 | | -** Add a new JSON_SUBST node. The node immediately following |
| 203792 | | -** this new node will be the substitute content for iNode. |
| 203793 | | -*/ |
| 203794 | | -static int jsonParseAddSubstNode( |
| 203795 | | - JsonParse *pParse, /* Add the JSON_SUBST here */ |
| 203796 | | - u32 iNode /* References this node */ |
| 203797 | | -){ |
| 203798 | | - int idx = jsonParseAddNode(pParse, JSON_SUBST, iNode, 0); |
| 203799 | | - if( pParse->oom ) return -1; |
| 203800 | | - pParse->aNode[iNode].jnFlags |= JNODE_REPLACE; |
| 203801 | | - pParse->aNode[idx].eU = 4; |
| 203802 | | - pParse->aNode[idx].u.iPrev = pParse->iSubst; |
| 203803 | | - pParse->iSubst = idx; |
| 203804 | | - pParse->hasMod = 1; |
| 203805 | | - pParse->useMod = 1; |
| 203806 | | - return idx; |
| 203807 | | -} |
| 203808 | | - |
| 203809 | 203851 | /* |
| 203810 | 203852 | ** Return true if z[] begins with 2 (or more) hexadecimal digits |
| 203811 | 203853 | */ |
| 203812 | 203854 | static int jsonIs2Hex(const char *z){ |
| 203813 | 203855 | return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]); |
| | @@ -203957,101 +203999,542 @@ |
| 203957 | 203999 | char eType; |
| 203958 | 204000 | char nRepl; |
| 203959 | 204001 | char *zMatch; |
| 203960 | 204002 | char *zRepl; |
| 203961 | 204003 | } aNanInfName[] = { |
| 203962 | | - { 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" }, |
| 203963 | | - { 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" }, |
| 203964 | | - { 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" }, |
| 203965 | | - { 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" }, |
| 203966 | | - { 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" }, |
| 203967 | | -}; |
| 203968 | | - |
| 203969 | | -/* |
| 203970 | | -** Parse a single JSON value which begins at pParse->zJson[i]. Return the |
| 203971 | | -** index of the first character past the end of the value parsed. |
| 203972 | | -** |
| 203973 | | -** Special return values: |
| 204004 | + { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" }, |
| 204005 | + { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" }, |
| 204006 | + { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" }, |
| 204007 | + { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" }, |
| 204008 | + { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" }, |
| 204009 | +}; |
| 204010 | + |
| 204011 | + |
| 204012 | +/* |
| 204013 | +** Report the wrong number of arguments for json_insert(), json_replace() |
| 204014 | +** or json_set(). |
| 204015 | +*/ |
| 204016 | +static void jsonWrongNumArgs( |
| 204017 | + sqlite3_context *pCtx, |
| 204018 | + const char *zFuncName |
| 204019 | +){ |
| 204020 | + char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", |
| 204021 | + zFuncName); |
| 204022 | + sqlite3_result_error(pCtx, zMsg, -1); |
| 204023 | + sqlite3_free(zMsg); |
| 204024 | +} |
| 204025 | + |
| 204026 | +/**************************************************************************** |
| 204027 | +** Utility routines for dealing with the binary BLOB representation of JSON |
| 204028 | +****************************************************************************/ |
| 204029 | + |
| 204030 | +/* |
| 204031 | +** Expand pParse->aBlob so that it holds at least N bytes. |
| 204032 | +** |
| 204033 | +** Return the number of errors. |
| 204034 | +*/ |
| 204035 | +static int jsonBlobExpand(JsonParse *pParse, u32 N){ |
| 204036 | + u8 *aNew; |
| 204037 | + u32 t; |
| 204038 | + assert( N>pParse->nBlobAlloc ); |
| 204039 | + if( pParse->nBlobAlloc==0 ){ |
| 204040 | + t = 100; |
| 204041 | + }else{ |
| 204042 | + t = pParse->nBlobAlloc*2; |
| 204043 | + } |
| 204044 | + if( t<N ) t = N+100; |
| 204045 | + aNew = sqlite3_realloc64( pParse->aBlob, t ); |
| 204046 | + if( aNew==0 ){ pParse->oom = 1; return 1; } |
| 204047 | + pParse->aBlob = aNew; |
| 204048 | + pParse->nBlobAlloc = t; |
| 204049 | + return 0; |
| 204050 | +} |
| 204051 | + |
| 204052 | +/* |
| 204053 | +** If pParse->aBlob is not previously editable (because it is taken |
| 204054 | +** from sqlite3_value_blob(), as indicated by the fact that |
| 204055 | +** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable |
| 204056 | +** by making a copy into space obtained from malloc. |
| 204057 | +** |
| 204058 | +** Return true on success. Return false on OOM. |
| 204059 | +*/ |
| 204060 | +static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){ |
| 204061 | + u8 *aOld; |
| 204062 | + u32 nSize; |
| 204063 | + assert( !pParse->bReadOnly ); |
| 204064 | + if( pParse->oom ) return 0; |
| 204065 | + if( pParse->nBlobAlloc>0 ) return 1; |
| 204066 | + aOld = pParse->aBlob; |
| 204067 | + nSize = pParse->nBlob + nExtra; |
| 204068 | + pParse->aBlob = 0; |
| 204069 | + if( jsonBlobExpand(pParse, nSize) ){ |
| 204070 | + return 0; |
| 204071 | + } |
| 204072 | + assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra ); |
| 204073 | + memcpy(pParse->aBlob, aOld, pParse->nBlob); |
| 204074 | + return 1; |
| 204075 | +} |
| 204076 | + |
| 204077 | +/* Expand pParse->aBlob and append one bytes. |
| 204078 | +*/ |
| 204079 | +static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte( |
| 204080 | + JsonParse *pParse, |
| 204081 | + u8 c |
| 204082 | +){ |
| 204083 | + jsonBlobExpand(pParse, pParse->nBlob+1); |
| 204084 | + if( pParse->oom==0 ){ |
| 204085 | + assert( pParse->nBlob+1<=pParse->nBlobAlloc ); |
| 204086 | + pParse->aBlob[pParse->nBlob++] = c; |
| 204087 | + } |
| 204088 | +} |
| 204089 | + |
| 204090 | +/* Append a single character. |
| 204091 | +*/ |
| 204092 | +static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){ |
| 204093 | + if( pParse->nBlob >= pParse->nBlobAlloc ){ |
| 204094 | + jsonBlobExpandAndAppendOneByte(pParse, c); |
| 204095 | + }else{ |
| 204096 | + pParse->aBlob[pParse->nBlob++] = c; |
| 204097 | + } |
| 204098 | +} |
| 204099 | + |
| 204100 | +/* Slow version of jsonBlobAppendNode() that first resizes the |
| 204101 | +** pParse->aBlob structure. |
| 204102 | +*/ |
| 204103 | +static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*); |
| 204104 | +static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( |
| 204105 | + JsonParse *pParse, |
| 204106 | + u8 eType, |
| 204107 | + u32 szPayload, |
| 204108 | + const void *aPayload |
| 204109 | +){ |
| 204110 | + if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; |
| 204111 | + jsonBlobAppendNode(pParse, eType, szPayload, aPayload); |
| 204112 | +} |
| 204113 | + |
| 204114 | + |
| 204115 | +/* Append an node type byte together with the payload size and |
| 204116 | +** possibly also the payload. |
| 204117 | +** |
| 204118 | +** If aPayload is not NULL, then it is a pointer to the payload which |
| 204119 | +** is also appended. If aPayload is NULL, the pParse->aBlob[] array |
| 204120 | +** is resized (if necessary) so that it is big enough to hold the |
| 204121 | +** payload, but the payload is not appended and pParse->nBlob is left |
| 204122 | +** pointing to where the first byte of payload will eventually be. |
| 204123 | +*/ |
| 204124 | +static void jsonBlobAppendNode( |
| 204125 | + JsonParse *pParse, /* The JsonParse object under construction */ |
| 204126 | + u8 eType, /* Node type. One of JSONB_* */ |
| 204127 | + u32 szPayload, /* Number of bytes of payload */ |
| 204128 | + const void *aPayload /* The payload. Might be NULL */ |
| 204129 | +){ |
| 204130 | + u8 *a; |
| 204131 | + if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){ |
| 204132 | + jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload); |
| 204133 | + return; |
| 204134 | + } |
| 204135 | + assert( pParse->aBlob!=0 ); |
| 204136 | + a = &pParse->aBlob[pParse->nBlob]; |
| 204137 | + if( szPayload<=11 ){ |
| 204138 | + a[0] = eType | (szPayload<<4); |
| 204139 | + pParse->nBlob += 1; |
| 204140 | + }else if( szPayload<=0xff ){ |
| 204141 | + a[0] = eType | 0xc0; |
| 204142 | + a[1] = szPayload & 0xff; |
| 204143 | + pParse->nBlob += 2; |
| 204144 | + }else if( szPayload<=0xffff ){ |
| 204145 | + a[0] = eType | 0xd0; |
| 204146 | + a[1] = (szPayload >> 8) & 0xff; |
| 204147 | + a[2] = szPayload & 0xff; |
| 204148 | + pParse->nBlob += 3; |
| 204149 | + }else{ |
| 204150 | + a[0] = eType | 0xe0; |
| 204151 | + a[1] = (szPayload >> 24) & 0xff; |
| 204152 | + a[2] = (szPayload >> 16) & 0xff; |
| 204153 | + a[3] = (szPayload >> 8) & 0xff; |
| 204154 | + a[4] = szPayload & 0xff; |
| 204155 | + pParse->nBlob += 5; |
| 204156 | + } |
| 204157 | + if( aPayload ){ |
| 204158 | + pParse->nBlob += szPayload; |
| 204159 | + memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload); |
| 204160 | + } |
| 204161 | +} |
| 204162 | + |
| 204163 | +/* Change the payload size for the node at index i to be szPayload. |
| 204164 | +*/ |
| 204165 | +static int jsonBlobChangePayloadSize( |
| 204166 | + JsonParse *pParse, |
| 204167 | + u32 i, |
| 204168 | + u32 szPayload |
| 204169 | +){ |
| 204170 | + u8 *a; |
| 204171 | + u8 szType; |
| 204172 | + u8 nExtra; |
| 204173 | + u8 nNeeded; |
| 204174 | + int delta; |
| 204175 | + if( pParse->oom ) return 0; |
| 204176 | + a = &pParse->aBlob[i]; |
| 204177 | + szType = a[0]>>4; |
| 204178 | + if( szType<=11 ){ |
| 204179 | + nExtra = 0; |
| 204180 | + }else if( szType==12 ){ |
| 204181 | + nExtra = 1; |
| 204182 | + }else if( szType==13 ){ |
| 204183 | + nExtra = 2; |
| 204184 | + }else{ |
| 204185 | + nExtra = 4; |
| 204186 | + } |
| 204187 | + if( szPayload<=11 ){ |
| 204188 | + nNeeded = 0; |
| 204189 | + }else if( szPayload<=0xff ){ |
| 204190 | + nNeeded = 1; |
| 204191 | + }else if( szPayload<=0xffff ){ |
| 204192 | + nNeeded = 2; |
| 204193 | + }else{ |
| 204194 | + nNeeded = 4; |
| 204195 | + } |
| 204196 | + delta = nNeeded - nExtra; |
| 204197 | + if( delta ){ |
| 204198 | + u32 newSize = pParse->nBlob + delta; |
| 204199 | + if( delta>0 ){ |
| 204200 | + if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){ |
| 204201 | + return 0; /* OOM error. Error state recorded in pParse->oom. */ |
| 204202 | + } |
| 204203 | + a = &pParse->aBlob[i]; |
| 204204 | + memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1)); |
| 204205 | + }else{ |
| 204206 | + memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta)); |
| 204207 | + } |
| 204208 | + pParse->nBlob = newSize; |
| 204209 | + } |
| 204210 | + if( nNeeded==0 ){ |
| 204211 | + a[0] = (a[0] & 0x0f) | (szPayload<<4); |
| 204212 | + }else if( nNeeded==1 ){ |
| 204213 | + a[0] = (a[0] & 0x0f) | 0xc0; |
| 204214 | + a[1] = szPayload & 0xff; |
| 204215 | + }else if( nNeeded==2 ){ |
| 204216 | + a[0] = (a[0] & 0x0f) | 0xd0; |
| 204217 | + a[1] = (szPayload >> 8) & 0xff; |
| 204218 | + a[2] = szPayload & 0xff; |
| 204219 | + }else{ |
| 204220 | + a[0] = (a[0] & 0x0f) | 0xe0; |
| 204221 | + a[1] = (szPayload >> 24) & 0xff; |
| 204222 | + a[2] = (szPayload >> 16) & 0xff; |
| 204223 | + a[3] = (szPayload >> 8) & 0xff; |
| 204224 | + a[4] = szPayload & 0xff; |
| 204225 | + } |
| 204226 | + return delta; |
| 204227 | +} |
| 204228 | + |
| 204229 | +/* |
| 204230 | +** If z[0] is 'u' and is followed by exactly 4 hexadecimal character, |
| 204231 | +** then set *pOp to JSONB_TEXTJ and return true. If not, do not make |
| 204232 | +** any changes to *pOp and return false. |
| 204233 | +*/ |
| 204234 | +static int jsonIs4HexB(const char *z, int *pOp){ |
| 204235 | + if( z[0]!='u' ) return 0; |
| 204236 | + if( !sqlite3Isxdigit(z[1]) ) return 0; |
| 204237 | + if( !sqlite3Isxdigit(z[2]) ) return 0; |
| 204238 | + if( !sqlite3Isxdigit(z[3]) ) return 0; |
| 204239 | + if( !sqlite3Isxdigit(z[4]) ) return 0; |
| 204240 | + *pOp = JSONB_TEXTJ; |
| 204241 | + return 1; |
| 204242 | +} |
| 204243 | + |
| 204244 | + |
| 204245 | +/* |
| 204246 | +** Check a single element of the JSONB in pParse for validity. |
| 204247 | +** |
| 204248 | +** The element to be checked starts at offset i and must end at on the |
| 204249 | +** last byte before iEnd. |
| 204250 | +** |
| 204251 | +** Return 0 if everything is correct. Return the 1-based byte offset of the |
| 204252 | +** error if a problem is detected. (In other words, if the error is at offset |
| 204253 | +** 0, return 1). |
| 204254 | +*/ |
| 204255 | +static u32 jsonbValidityCheck( |
| 204256 | + const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */ |
| 204257 | + u32 i, /* Start of element as pParse->aBlob[i] */ |
| 204258 | + u32 iEnd, /* One more than the last byte of the element */ |
| 204259 | + u32 iDepth /* Current nesting depth */ |
| 204260 | +){ |
| 204261 | + u32 n, sz, j, k; |
| 204262 | + const u8 *z; |
| 204263 | + u8 x; |
| 204264 | + if( iDepth>JSON_MAX_DEPTH ) return i+1; |
| 204265 | + sz = 0; |
| 204266 | + n = jsonbPayloadSize(pParse, i, &sz); |
| 204267 | + if( NEVER(n==0) ) return i+1; /* Checked by caller */ |
| 204268 | + if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */ |
| 204269 | + z = pParse->aBlob; |
| 204270 | + x = z[i] & 0x0f; |
| 204271 | + switch( x ){ |
| 204272 | + case JSONB_NULL: |
| 204273 | + case JSONB_TRUE: |
| 204274 | + case JSONB_FALSE: { |
| 204275 | + return n+sz==1 ? 0 : i+1; |
| 204276 | + } |
| 204277 | + case JSONB_INT: { |
| 204278 | + if( sz<1 ) return i+1; |
| 204279 | + j = i+n; |
| 204280 | + if( z[j]=='-' ){ |
| 204281 | + j++; |
| 204282 | + if( sz<2 ) return i+1; |
| 204283 | + } |
| 204284 | + k = i+n+sz; |
| 204285 | + while( j<k ){ |
| 204286 | + if( sqlite3Isdigit(z[j]) ){ |
| 204287 | + j++; |
| 204288 | + }else{ |
| 204289 | + return j+1; |
| 204290 | + } |
| 204291 | + } |
| 204292 | + return 0; |
| 204293 | + } |
| 204294 | + case JSONB_INT5: { |
| 204295 | + if( sz<3 ) return i+1; |
| 204296 | + j = i+n; |
| 204297 | + if( z[j]=='-' ){ |
| 204298 | + if( sz<4 ) return i+1; |
| 204299 | + j++; |
| 204300 | + } |
| 204301 | + if( z[j]!='0' ) return i+1; |
| 204302 | + if( z[j+1]!='x' && z[j+1]!='X' ) return j+2; |
| 204303 | + j += 2; |
| 204304 | + k = i+n+sz; |
| 204305 | + while( j<k ){ |
| 204306 | + if( sqlite3Isxdigit(z[j]) ){ |
| 204307 | + j++; |
| 204308 | + }else{ |
| 204309 | + return j+1; |
| 204310 | + } |
| 204311 | + } |
| 204312 | + return 0; |
| 204313 | + } |
| 204314 | + case JSONB_FLOAT: |
| 204315 | + case JSONB_FLOAT5: { |
| 204316 | + u8 seen = 0; /* 0: initial. 1: '.' seen 2: 'e' seen */ |
| 204317 | + if( sz<2 ) return i+1; |
| 204318 | + j = i+n; |
| 204319 | + k = j+sz; |
| 204320 | + if( z[j]=='-' ){ |
| 204321 | + j++; |
| 204322 | + if( sz<3 ) return i+1; |
| 204323 | + } |
| 204324 | + if( z[j]=='.' ){ |
| 204325 | + if( x==JSONB_FLOAT ) return j+1; |
| 204326 | + if( !sqlite3Isdigit(z[j+1]) ) return j+1; |
| 204327 | + j += 2; |
| 204328 | + seen = 1; |
| 204329 | + }else if( z[j]=='0' && x==JSONB_FLOAT ){ |
| 204330 | + if( j+3>k ) return j+1; |
| 204331 | + if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1; |
| 204332 | + j++; |
| 204333 | + } |
| 204334 | + for(; j<k; j++){ |
| 204335 | + if( sqlite3Isdigit(z[j]) ) continue; |
| 204336 | + if( z[j]=='.' ){ |
| 204337 | + if( seen>0 ) return j+1; |
| 204338 | + if( x==JSONB_FLOAT && (j==k-1 || !sqlite3Isdigit(z[j+1])) ){ |
| 204339 | + return j+1; |
| 204340 | + } |
| 204341 | + seen = 1; |
| 204342 | + continue; |
| 204343 | + } |
| 204344 | + if( z[j]=='e' || z[j]=='E' ){ |
| 204345 | + if( seen==2 ) return j+1; |
| 204346 | + if( j==k-1 ) return j+1; |
| 204347 | + if( z[j+1]=='+' || z[j+1]=='-' ){ |
| 204348 | + j++; |
| 204349 | + if( j==k-1 ) return j+1; |
| 204350 | + } |
| 204351 | + seen = 2; |
| 204352 | + continue; |
| 204353 | + } |
| 204354 | + return j+1; |
| 204355 | + } |
| 204356 | + if( seen==0 ) return i+1; |
| 204357 | + return 0; |
| 204358 | + } |
| 204359 | + case JSONB_TEXT: { |
| 204360 | + j = i+n; |
| 204361 | + k = j+sz; |
| 204362 | + while( j<k ){ |
| 204363 | + if( !jsonIsOk[z[j]] && z[j]!='\'' ) return j+1; |
| 204364 | + j++; |
| 204365 | + } |
| 204366 | + return 0; |
| 204367 | + } |
| 204368 | + case JSONB_TEXTJ: |
| 204369 | + case JSONB_TEXT5: { |
| 204370 | + j = i+n; |
| 204371 | + k = j+sz; |
| 204372 | + while( j<k ){ |
| 204373 | + if( !jsonIsOk[z[j]] && z[j]!='\'' ){ |
| 204374 | + if( z[j]=='"' ){ |
| 204375 | + if( x==JSONB_TEXTJ ) return j+1; |
| 204376 | + }else if( z[j]!='\\' || j+1>=k ){ |
| 204377 | + return j+1; |
| 204378 | + }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){ |
| 204379 | + j++; |
| 204380 | + }else if( z[j+1]=='u' ){ |
| 204381 | + if( j+5>=k ) return j+1; |
| 204382 | + if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1; |
| 204383 | + j++; |
| 204384 | + }else if( x!=JSONB_TEXT5 ){ |
| 204385 | + return j+1; |
| 204386 | + }else{ |
| 204387 | + u32 c = 0; |
| 204388 | + u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c); |
| 204389 | + if( c==0xfffd ) return j+1; |
| 204390 | + j += szC - 1; |
| 204391 | + } |
| 204392 | + } |
| 204393 | + j++; |
| 204394 | + } |
| 204395 | + return 0; |
| 204396 | + } |
| 204397 | + case JSONB_TEXTRAW: { |
| 204398 | + return 0; |
| 204399 | + } |
| 204400 | + case JSONB_ARRAY: { |
| 204401 | + u32 sub; |
| 204402 | + j = i+n; |
| 204403 | + k = j+sz; |
| 204404 | + while( j<k ){ |
| 204405 | + sz = 0; |
| 204406 | + n = jsonbPayloadSize(pParse, j, &sz); |
| 204407 | + if( n==0 ) return j+1; |
| 204408 | + if( j+n+sz>k ) return j+1; |
| 204409 | + sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); |
| 204410 | + if( sub ) return sub; |
| 204411 | + j += n + sz; |
| 204412 | + } |
| 204413 | + assert( j==k ); |
| 204414 | + return 0; |
| 204415 | + } |
| 204416 | + case JSONB_OBJECT: { |
| 204417 | + u32 cnt = 0; |
| 204418 | + u32 sub; |
| 204419 | + j = i+n; |
| 204420 | + k = j+sz; |
| 204421 | + while( j<k ){ |
| 204422 | + sz = 0; |
| 204423 | + n = jsonbPayloadSize(pParse, j, &sz); |
| 204424 | + if( n==0 ) return j+1; |
| 204425 | + if( j+n+sz>k ) return j+1; |
| 204426 | + if( (cnt & 1)==0 ){ |
| 204427 | + x = z[j] & 0x0f; |
| 204428 | + if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1; |
| 204429 | + } |
| 204430 | + sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1); |
| 204431 | + if( sub ) return sub; |
| 204432 | + cnt++; |
| 204433 | + j += n + sz; |
| 204434 | + } |
| 204435 | + assert( j==k ); |
| 204436 | + if( (cnt & 1)!=0 ) return j+1; |
| 204437 | + return 0; |
| 204438 | + } |
| 204439 | + default: { |
| 204440 | + return i+1; |
| 204441 | + } |
| 204442 | + } |
| 204443 | +} |
| 204444 | + |
| 204445 | +/* |
| 204446 | +** Translate a single element of JSON text at pParse->zJson[i] into |
| 204447 | +** its equivalent binary JSONB representation. Append the translation into |
| 204448 | +** pParse->aBlob[] beginning at pParse->nBlob. The size of |
| 204449 | +** pParse->aBlob[] is increased as necessary. |
| 204450 | +** |
| 204451 | +** Return the index of the first character past the end of the element parsed, |
| 204452 | +** or one of the following special result codes: |
| 203974 | 204453 | ** |
| 203975 | 204454 | ** 0 End of input |
| 203976 | | -** -1 Syntax error |
| 203977 | | -** -2 '}' seen |
| 203978 | | -** -3 ']' seen |
| 203979 | | -** -4 ',' seen |
| 203980 | | -** -5 ':' seen |
| 204455 | +** -1 Syntax error or OOM |
| 204456 | +** -2 '}' seen \ |
| 204457 | +** -3 ']' seen \___ For these returns, pParse->iErr is set to |
| 204458 | +** -4 ',' seen / the index in zJson[] of the seen character |
| 204459 | +** -5 ':' seen / |
| 203981 | 204460 | */ |
| 203982 | | -static int jsonParseValue(JsonParse *pParse, u32 i){ |
| 204461 | +static int jsonXlateTextToBlob(JsonParse *pParse, u32 i){ |
| 203983 | 204462 | char c; |
| 203984 | 204463 | u32 j; |
| 203985 | | - int iThis; |
| 204464 | + u32 iThis, iStart; |
| 203986 | 204465 | int x; |
| 203987 | | - JsonNode *pNode; |
| 204466 | + u8 t; |
| 203988 | 204467 | const char *z = pParse->zJson; |
| 203989 | 204468 | json_parse_restart: |
| 203990 | 204469 | switch( (u8)z[i] ){ |
| 203991 | 204470 | case '{': { |
| 203992 | 204471 | /* Parse object */ |
| 203993 | | - iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); |
| 203994 | | - if( iThis<0 ) return -1; |
| 204472 | + iThis = pParse->nBlob; |
| 204473 | + jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0); |
| 203995 | 204474 | if( ++pParse->iDepth > JSON_MAX_DEPTH ){ |
| 203996 | 204475 | pParse->iErr = i; |
| 203997 | 204476 | return -1; |
| 203998 | 204477 | } |
| 204478 | + iStart = pParse->nBlob; |
| 203999 | 204479 | for(j=i+1;;j++){ |
| 204000 | | - u32 nNode = pParse->nNode; |
| 204001 | | - x = jsonParseValue(pParse, j); |
| 204480 | + u32 iBlob = pParse->nBlob; |
| 204481 | + x = jsonXlateTextToBlob(pParse, j); |
| 204002 | 204482 | if( x<=0 ){ |
| 204483 | + int op; |
| 204003 | 204484 | if( x==(-2) ){ |
| 204004 | 204485 | j = pParse->iErr; |
| 204005 | | - if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1; |
| 204486 | + if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1; |
| 204006 | 204487 | break; |
| 204007 | 204488 | } |
| 204008 | 204489 | j += json5Whitespace(&z[j]); |
| 204490 | + op = JSONB_TEXT; |
| 204009 | 204491 | if( sqlite3JsonId1(z[j]) |
| 204010 | | - || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2])) |
| 204492 | + || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op)) |
| 204011 | 204493 | ){ |
| 204012 | 204494 | int k = j+1; |
| 204013 | 204495 | while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0) |
| 204014 | | - || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2])) |
| 204496 | + || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op)) |
| 204015 | 204497 | ){ |
| 204016 | 204498 | k++; |
| 204017 | 204499 | } |
| 204018 | | - jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]); |
| 204500 | + assert( iBlob==pParse->nBlob ); |
| 204501 | + jsonBlobAppendNode(pParse, op, k-j, &z[j]); |
| 204019 | 204502 | pParse->hasNonstd = 1; |
| 204020 | 204503 | x = k; |
| 204021 | 204504 | }else{ |
| 204022 | 204505 | if( x!=-1 ) pParse->iErr = j; |
| 204023 | 204506 | return -1; |
| 204024 | 204507 | } |
| 204025 | 204508 | } |
| 204026 | 204509 | if( pParse->oom ) return -1; |
| 204027 | | - pNode = &pParse->aNode[nNode]; |
| 204028 | | - if( pNode->eType!=JSON_STRING ){ |
| 204510 | + t = pParse->aBlob[iBlob] & 0x0f; |
| 204511 | + if( t<JSONB_TEXT || t>JSONB_TEXTRAW ){ |
| 204029 | 204512 | pParse->iErr = j; |
| 204030 | 204513 | return -1; |
| 204031 | 204514 | } |
| 204032 | | - pNode->jnFlags |= JNODE_LABEL; |
| 204033 | 204515 | j = x; |
| 204034 | 204516 | if( z[j]==':' ){ |
| 204035 | 204517 | j++; |
| 204036 | 204518 | }else{ |
| 204037 | | - if( fast_isspace(z[j]) ){ |
| 204038 | | - do{ j++; }while( fast_isspace(z[j]) ); |
| 204519 | + if( jsonIsspace(z[j]) ){ |
| 204520 | + /* strspn() is not helpful here */ |
| 204521 | + do{ j++; }while( jsonIsspace(z[j]) ); |
| 204039 | 204522 | if( z[j]==':' ){ |
| 204040 | 204523 | j++; |
| 204041 | 204524 | goto parse_object_value; |
| 204042 | 204525 | } |
| 204043 | 204526 | } |
| 204044 | | - x = jsonParseValue(pParse, j); |
| 204527 | + x = jsonXlateTextToBlob(pParse, j); |
| 204045 | 204528 | if( x!=(-5) ){ |
| 204046 | 204529 | if( x!=(-1) ) pParse->iErr = j; |
| 204047 | 204530 | return -1; |
| 204048 | 204531 | } |
| 204049 | 204532 | j = pParse->iErr+1; |
| 204050 | 204533 | } |
| 204051 | 204534 | parse_object_value: |
| 204052 | | - x = jsonParseValue(pParse, j); |
| 204535 | + x = jsonXlateTextToBlob(pParse, j); |
| 204053 | 204536 | if( x<=0 ){ |
| 204054 | 204537 | if( x!=(-1) ) pParse->iErr = j; |
| 204055 | 204538 | return -1; |
| 204056 | 204539 | } |
| 204057 | 204540 | j = x; |
| | @@ -204058,19 +204541,19 @@ |
| 204058 | 204541 | if( z[j]==',' ){ |
| 204059 | 204542 | continue; |
| 204060 | 204543 | }else if( z[j]=='}' ){ |
| 204061 | 204544 | break; |
| 204062 | 204545 | }else{ |
| 204063 | | - if( fast_isspace(z[j]) ){ |
| 204064 | | - do{ j++; }while( fast_isspace(z[j]) ); |
| 204546 | + if( jsonIsspace(z[j]) ){ |
| 204547 | + j += 1 + (u32)strspn(&z[j+1], jsonSpaces); |
| 204065 | 204548 | if( z[j]==',' ){ |
| 204066 | 204549 | continue; |
| 204067 | 204550 | }else if( z[j]=='}' ){ |
| 204068 | 204551 | break; |
| 204069 | 204552 | } |
| 204070 | 204553 | } |
| 204071 | | - x = jsonParseValue(pParse, j); |
| 204554 | + x = jsonXlateTextToBlob(pParse, j); |
| 204072 | 204555 | if( x==(-4) ){ |
| 204073 | 204556 | j = pParse->iErr; |
| 204074 | 204557 | continue; |
| 204075 | 204558 | } |
| 204076 | 204559 | if( x==(-2) ){ |
| | @@ -204079,29 +204562,30 @@ |
| 204079 | 204562 | } |
| 204080 | 204563 | } |
| 204081 | 204564 | pParse->iErr = j; |
| 204082 | 204565 | return -1; |
| 204083 | 204566 | } |
| 204084 | | - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; |
| 204567 | + jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); |
| 204085 | 204568 | pParse->iDepth--; |
| 204086 | 204569 | return j+1; |
| 204087 | 204570 | } |
| 204088 | 204571 | case '[': { |
| 204089 | 204572 | /* Parse array */ |
| 204090 | | - iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); |
| 204091 | | - if( iThis<0 ) return -1; |
| 204573 | + iThis = pParse->nBlob; |
| 204574 | + jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0); |
| 204575 | + iStart = pParse->nBlob; |
| 204576 | + if( pParse->oom ) return -1; |
| 204092 | 204577 | if( ++pParse->iDepth > JSON_MAX_DEPTH ){ |
| 204093 | 204578 | pParse->iErr = i; |
| 204094 | 204579 | return -1; |
| 204095 | 204580 | } |
| 204096 | | - memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); |
| 204097 | 204581 | for(j=i+1;;j++){ |
| 204098 | | - x = jsonParseValue(pParse, j); |
| 204582 | + x = jsonXlateTextToBlob(pParse, j); |
| 204099 | 204583 | if( x<=0 ){ |
| 204100 | 204584 | if( x==(-3) ){ |
| 204101 | 204585 | j = pParse->iErr; |
| 204102 | | - if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1; |
| 204586 | + if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1; |
| 204103 | 204587 | break; |
| 204104 | 204588 | } |
| 204105 | 204589 | if( x!=(-1) ) pParse->iErr = j; |
| 204106 | 204590 | return -1; |
| 204107 | 204591 | } |
| | @@ -204109,19 +204593,19 @@ |
| 204109 | 204593 | if( z[j]==',' ){ |
| 204110 | 204594 | continue; |
| 204111 | 204595 | }else if( z[j]==']' ){ |
| 204112 | 204596 | break; |
| 204113 | 204597 | }else{ |
| 204114 | | - if( fast_isspace(z[j]) ){ |
| 204115 | | - do{ j++; }while( fast_isspace(z[j]) ); |
| 204598 | + if( jsonIsspace(z[j]) ){ |
| 204599 | + j += 1 + (u32)strspn(&z[j+1], jsonSpaces); |
| 204116 | 204600 | if( z[j]==',' ){ |
| 204117 | 204601 | continue; |
| 204118 | 204602 | }else if( z[j]==']' ){ |
| 204119 | 204603 | break; |
| 204120 | 204604 | } |
| 204121 | 204605 | } |
| 204122 | | - x = jsonParseValue(pParse, j); |
| 204606 | + x = jsonXlateTextToBlob(pParse, j); |
| 204123 | 204607 | if( x==(-4) ){ |
| 204124 | 204608 | j = pParse->iErr; |
| 204125 | 204609 | continue; |
| 204126 | 204610 | } |
| 204127 | 204611 | if( x==(-3) ){ |
| | @@ -204130,86 +204614,98 @@ |
| 204130 | 204614 | } |
| 204131 | 204615 | } |
| 204132 | 204616 | pParse->iErr = j; |
| 204133 | 204617 | return -1; |
| 204134 | 204618 | } |
| 204135 | | - pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; |
| 204619 | + jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart); |
| 204136 | 204620 | pParse->iDepth--; |
| 204137 | 204621 | return j+1; |
| 204138 | 204622 | } |
| 204139 | 204623 | case '\'': { |
| 204140 | | - u8 jnFlags; |
| 204624 | + u8 opcode; |
| 204141 | 204625 | char cDelim; |
| 204142 | 204626 | pParse->hasNonstd = 1; |
| 204143 | | - jnFlags = JNODE_JSON5; |
| 204627 | + opcode = JSONB_TEXT; |
| 204144 | 204628 | goto parse_string; |
| 204145 | 204629 | case '"': |
| 204146 | 204630 | /* Parse string */ |
| 204147 | | - jnFlags = 0; |
| 204631 | + opcode = JSONB_TEXT; |
| 204148 | 204632 | parse_string: |
| 204149 | 204633 | cDelim = z[i]; |
| 204150 | | - for(j=i+1; 1; j++){ |
| 204151 | | - if( jsonIsOk[(unsigned char)z[j]] ) continue; |
| 204634 | + j = i+1; |
| 204635 | + while( 1 /*exit-by-break*/ ){ |
| 204636 | + if( jsonIsOk[(u8)z[j]] ){ |
| 204637 | + if( !jsonIsOk[(u8)z[j+1]] ){ |
| 204638 | + j += 1; |
| 204639 | + }else if( !jsonIsOk[(u8)z[j+2]] ){ |
| 204640 | + j += 2; |
| 204641 | + }else{ |
| 204642 | + j += 3; |
| 204643 | + continue; |
| 204644 | + } |
| 204645 | + } |
| 204152 | 204646 | c = z[j]; |
| 204153 | 204647 | if( c==cDelim ){ |
| 204154 | 204648 | break; |
| 204155 | 204649 | }else if( c=='\\' ){ |
| 204156 | 204650 | c = z[++j]; |
| 204157 | 204651 | if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' |
| 204158 | 204652 | || c=='n' || c=='r' || c=='t' |
| 204159 | 204653 | || (c=='u' && jsonIs4Hex(&z[j+1])) ){ |
| 204160 | | - jnFlags |= JNODE_ESCAPE; |
| 204654 | + if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; |
| 204161 | 204655 | }else if( c=='\'' || c=='0' || c=='v' || c=='\n' |
| 204162 | 204656 | || (0xe2==(u8)c && 0x80==(u8)z[j+1] |
| 204163 | 204657 | && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) |
| 204164 | 204658 | || (c=='x' && jsonIs2Hex(&z[j+1])) ){ |
| 204165 | | - jnFlags |= (JNODE_ESCAPE|JNODE_JSON5); |
| 204659 | + opcode = JSONB_TEXT5; |
| 204166 | 204660 | pParse->hasNonstd = 1; |
| 204167 | 204661 | }else if( c=='\r' ){ |
| 204168 | 204662 | if( z[j+1]=='\n' ) j++; |
| 204169 | | - jnFlags |= (JNODE_ESCAPE|JNODE_JSON5); |
| 204663 | + opcode = JSONB_TEXT5; |
| 204170 | 204664 | pParse->hasNonstd = 1; |
| 204171 | 204665 | }else{ |
| 204172 | 204666 | pParse->iErr = j; |
| 204173 | 204667 | return -1; |
| 204174 | 204668 | } |
| 204175 | 204669 | }else if( c<=0x1f ){ |
| 204176 | 204670 | /* Control characters are not allowed in strings */ |
| 204177 | 204671 | pParse->iErr = j; |
| 204178 | 204672 | return -1; |
| 204673 | + }else if( c=='"' ){ |
| 204674 | + opcode = JSONB_TEXT5; |
| 204179 | 204675 | } |
| 204676 | + j++; |
| 204180 | 204677 | } |
| 204181 | | - jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]); |
| 204678 | + jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]); |
| 204182 | 204679 | return j+1; |
| 204183 | 204680 | } |
| 204184 | 204681 | case 't': { |
| 204185 | 204682 | if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){ |
| 204186 | | - jsonParseAddNode(pParse, JSON_TRUE, 0, 0); |
| 204683 | + jsonBlobAppendOneByte(pParse, JSONB_TRUE); |
| 204187 | 204684 | return i+4; |
| 204188 | 204685 | } |
| 204189 | 204686 | pParse->iErr = i; |
| 204190 | 204687 | return -1; |
| 204191 | 204688 | } |
| 204192 | 204689 | case 'f': { |
| 204193 | 204690 | if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){ |
| 204194 | | - jsonParseAddNode(pParse, JSON_FALSE, 0, 0); |
| 204691 | + jsonBlobAppendOneByte(pParse, JSONB_FALSE); |
| 204195 | 204692 | return i+5; |
| 204196 | 204693 | } |
| 204197 | 204694 | pParse->iErr = i; |
| 204198 | 204695 | return -1; |
| 204199 | 204696 | } |
| 204200 | 204697 | case '+': { |
| 204201 | | - u8 seenDP, seenE, jnFlags; |
| 204698 | + u8 seenE; |
| 204202 | 204699 | pParse->hasNonstd = 1; |
| 204203 | | - jnFlags = JNODE_JSON5; |
| 204700 | + t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ |
| 204204 | 204701 | goto parse_number; |
| 204205 | 204702 | case '.': |
| 204206 | 204703 | if( sqlite3Isdigit(z[i+1]) ){ |
| 204207 | 204704 | pParse->hasNonstd = 1; |
| 204208 | | - jnFlags = JNODE_JSON5; |
| 204705 | + t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ |
| 204209 | 204706 | seenE = 0; |
| 204210 | | - seenDP = JSON_REAL; |
| 204211 | 204707 | goto parse_number_2; |
| 204212 | 204708 | } |
| 204213 | 204709 | pParse->iErr = i; |
| 204214 | 204710 | return -1; |
| 204215 | 204711 | case '-': |
| | @@ -204222,25 +204718,24 @@ |
| 204222 | 204718 | case '6': |
| 204223 | 204719 | case '7': |
| 204224 | 204720 | case '8': |
| 204225 | 204721 | case '9': |
| 204226 | 204722 | /* Parse number */ |
| 204227 | | - jnFlags = 0; |
| 204723 | + t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */ |
| 204228 | 204724 | parse_number: |
| 204229 | | - seenDP = JSON_INT; |
| 204230 | 204725 | seenE = 0; |
| 204231 | 204726 | assert( '-' < '0' ); |
| 204232 | 204727 | assert( '+' < '0' ); |
| 204233 | 204728 | assert( '.' < '0' ); |
| 204234 | 204729 | c = z[i]; |
| 204235 | 204730 | |
| 204236 | 204731 | if( c<='0' ){ |
| 204237 | 204732 | if( c=='0' ){ |
| 204238 | 204733 | if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){ |
| 204239 | | - assert( seenDP==JSON_INT ); |
| 204734 | + assert( t==0x00 ); |
| 204240 | 204735 | pParse->hasNonstd = 1; |
| 204241 | | - jnFlags |= JNODE_JSON5; |
| 204736 | + t = 0x01; |
| 204242 | 204737 | for(j=i+3; sqlite3Isxdigit(z[j]); j++){} |
| 204243 | 204738 | goto parse_number_finish; |
| 204244 | 204739 | }else if( sqlite3Isdigit(z[i+1]) ){ |
| 204245 | 204740 | pParse->iErr = i+1; |
| 204246 | 204741 | return -1; |
| | @@ -204253,19 +204748,19 @@ |
| 204253 | 204748 | if( (z[i+1]=='I' || z[i+1]=='i') |
| 204254 | 204749 | && sqlite3StrNICmp(&z[i+1], "inf",3)==0 |
| 204255 | 204750 | ){ |
| 204256 | 204751 | pParse->hasNonstd = 1; |
| 204257 | 204752 | if( z[i]=='-' ){ |
| 204258 | | - jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999"); |
| 204753 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999"); |
| 204259 | 204754 | }else{ |
| 204260 | | - jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999"); |
| 204755 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); |
| 204261 | 204756 | } |
| 204262 | 204757 | return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4); |
| 204263 | 204758 | } |
| 204264 | 204759 | if( z[i+1]=='.' ){ |
| 204265 | 204760 | pParse->hasNonstd = 1; |
| 204266 | | - jnFlags |= JNODE_JSON5; |
| 204761 | + t |= 0x01; |
| 204267 | 204762 | goto parse_number_2; |
| 204268 | 204763 | } |
| 204269 | 204764 | pParse->iErr = i; |
| 204270 | 204765 | return -1; |
| 204271 | 204766 | } |
| | @@ -204273,44 +204768,45 @@ |
| 204273 | 204768 | if( sqlite3Isdigit(z[i+2]) ){ |
| 204274 | 204769 | pParse->iErr = i+1; |
| 204275 | 204770 | return -1; |
| 204276 | 204771 | }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){ |
| 204277 | 204772 | pParse->hasNonstd = 1; |
| 204278 | | - jnFlags |= JNODE_JSON5; |
| 204773 | + t |= 0x01; |
| 204279 | 204774 | for(j=i+4; sqlite3Isxdigit(z[j]); j++){} |
| 204280 | 204775 | goto parse_number_finish; |
| 204281 | 204776 | } |
| 204282 | 204777 | } |
| 204283 | 204778 | } |
| 204284 | 204779 | } |
| 204780 | + |
| 204285 | 204781 | parse_number_2: |
| 204286 | 204782 | for(j=i+1;; j++){ |
| 204287 | 204783 | c = z[j]; |
| 204288 | 204784 | if( sqlite3Isdigit(c) ) continue; |
| 204289 | 204785 | if( c=='.' ){ |
| 204290 | | - if( seenDP==JSON_REAL ){ |
| 204786 | + if( (t & 0x02)!=0 ){ |
| 204291 | 204787 | pParse->iErr = j; |
| 204292 | 204788 | return -1; |
| 204293 | 204789 | } |
| 204294 | | - seenDP = JSON_REAL; |
| 204790 | + t |= 0x02; |
| 204295 | 204791 | continue; |
| 204296 | 204792 | } |
| 204297 | 204793 | if( c=='e' || c=='E' ){ |
| 204298 | 204794 | if( z[j-1]<'0' ){ |
| 204299 | 204795 | if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ |
| 204300 | 204796 | pParse->hasNonstd = 1; |
| 204301 | | - jnFlags |= JNODE_JSON5; |
| 204797 | + t |= 0x01; |
| 204302 | 204798 | }else{ |
| 204303 | 204799 | pParse->iErr = j; |
| 204304 | 204800 | return -1; |
| 204305 | 204801 | } |
| 204306 | 204802 | } |
| 204307 | 204803 | if( seenE ){ |
| 204308 | 204804 | pParse->iErr = j; |
| 204309 | 204805 | return -1; |
| 204310 | 204806 | } |
| 204311 | | - seenDP = JSON_REAL; |
| 204807 | + t |= 0x02; |
| 204312 | 204808 | seenE = 1; |
| 204313 | 204809 | c = z[j+1]; |
| 204314 | 204810 | if( c=='+' || c=='-' ){ |
| 204315 | 204811 | j++; |
| 204316 | 204812 | c = z[j+1]; |
| | @@ -204324,18 +204820,22 @@ |
| 204324 | 204820 | break; |
| 204325 | 204821 | } |
| 204326 | 204822 | if( z[j-1]<'0' ){ |
| 204327 | 204823 | if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ |
| 204328 | 204824 | pParse->hasNonstd = 1; |
| 204329 | | - jnFlags |= JNODE_JSON5; |
| 204825 | + t |= 0x01; |
| 204330 | 204826 | }else{ |
| 204331 | 204827 | pParse->iErr = j; |
| 204332 | 204828 | return -1; |
| 204333 | 204829 | } |
| 204334 | 204830 | } |
| 204335 | 204831 | parse_number_finish: |
| 204336 | | - jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]); |
| 204832 | + assert( JSONB_INT+0x01==JSONB_INT5 ); |
| 204833 | + assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 ); |
| 204834 | + assert( JSONB_INT+0x02==JSONB_FLOAT ); |
| 204835 | + if( z[i]=='+' ) i++; |
| 204836 | + jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]); |
| 204337 | 204837 | return j; |
| 204338 | 204838 | } |
| 204339 | 204839 | case '}': { |
| 204340 | 204840 | pParse->iErr = i; |
| 204341 | 204841 | return -2; /* End of {...} */ |
| | @@ -204357,13 +204857,11 @@ |
| 204357 | 204857 | } |
| 204358 | 204858 | case 0x09: |
| 204359 | 204859 | case 0x0a: |
| 204360 | 204860 | case 0x0d: |
| 204361 | 204861 | case 0x20: { |
| 204362 | | - do{ |
| 204363 | | - i++; |
| 204364 | | - }while( fast_isspace(z[i]) ); |
| 204862 | + i += 1 + (u32)strspn(&z[i+1], jsonSpaces); |
| 204365 | 204863 | goto json_parse_restart; |
| 204366 | 204864 | } |
| 204367 | 204865 | case 0x0b: |
| 204368 | 204866 | case 0x0c: |
| 204369 | 204867 | case '/': |
| | @@ -204381,11 +204879,11 @@ |
| 204381 | 204879 | pParse->iErr = i; |
| 204382 | 204880 | return -1; |
| 204383 | 204881 | } |
| 204384 | 204882 | case 'n': { |
| 204385 | 204883 | if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){ |
| 204386 | | - jsonParseAddNode(pParse, JSON_NULL, 0, 0); |
| 204884 | + jsonBlobAppendOneByte(pParse, JSONB_NULL); |
| 204387 | 204885 | return i+4; |
| 204388 | 204886 | } |
| 204389 | 204887 | /* fall-through into the default case that checks for NaN */ |
| 204390 | 204888 | } |
| 204391 | 204889 | default: { |
| | @@ -204397,43 +204895,53 @@ |
| 204397 | 204895 | nn = aNanInfName[k].n; |
| 204398 | 204896 | if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){ |
| 204399 | 204897 | continue; |
| 204400 | 204898 | } |
| 204401 | 204899 | if( sqlite3Isalnum(z[i+nn]) ) continue; |
| 204402 | | - jsonParseAddNode(pParse, aNanInfName[k].eType, |
| 204403 | | - aNanInfName[k].nRepl, aNanInfName[k].zRepl); |
| 204900 | + if( aNanInfName[k].eType==JSONB_FLOAT ){ |
| 204901 | + jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999"); |
| 204902 | + }else{ |
| 204903 | + jsonBlobAppendOneByte(pParse, JSONB_NULL); |
| 204904 | + } |
| 204404 | 204905 | pParse->hasNonstd = 1; |
| 204405 | 204906 | return i + nn; |
| 204406 | 204907 | } |
| 204407 | 204908 | pParse->iErr = i; |
| 204408 | 204909 | return -1; /* Syntax error */ |
| 204409 | 204910 | } |
| 204410 | 204911 | } /* End switch(z[i]) */ |
| 204411 | 204912 | } |
| 204913 | + |
| 204412 | 204914 | |
| 204413 | 204915 | /* |
| 204414 | 204916 | ** Parse a complete JSON string. Return 0 on success or non-zero if there |
| 204415 | 204917 | ** are any errors. If an error occurs, free all memory held by pParse, |
| 204416 | 204918 | ** but not pParse itself. |
| 204417 | 204919 | ** |
| 204418 | 204920 | ** pParse must be initialized to an empty parse object prior to calling |
| 204419 | 204921 | ** this routine. |
| 204420 | 204922 | */ |
| 204421 | | -static int jsonParse( |
| 204923 | +static int jsonConvertTextToBlob( |
| 204422 | 204924 | JsonParse *pParse, /* Initialize and fill this JsonParse object */ |
| 204423 | 204925 | sqlite3_context *pCtx /* Report errors here */ |
| 204424 | 204926 | ){ |
| 204425 | 204927 | int i; |
| 204426 | 204928 | const char *zJson = pParse->zJson; |
| 204427 | | - i = jsonParseValue(pParse, 0); |
| 204929 | + i = jsonXlateTextToBlob(pParse, 0); |
| 204428 | 204930 | if( pParse->oom ) i = -1; |
| 204429 | 204931 | if( i>0 ){ |
| 204932 | +#ifdef SQLITE_DEBUG |
| 204430 | 204933 | assert( pParse->iDepth==0 ); |
| 204431 | | - while( fast_isspace(zJson[i]) ) i++; |
| 204934 | + if( sqlite3Config.bJsonSelfcheck ){ |
| 204935 | + assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 ); |
| 204936 | + } |
| 204937 | +#endif |
| 204938 | + while( jsonIsspace(zJson[i]) ) i++; |
| 204432 | 204939 | if( zJson[i] ){ |
| 204433 | 204940 | i += json5Whitespace(&zJson[i]); |
| 204434 | 204941 | if( zJson[i] ){ |
| 204942 | + if( pCtx ) sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 204435 | 204943 | jsonParseReset(pParse); |
| 204436 | 204944 | return 1; |
| 204437 | 204945 | } |
| 204438 | 204946 | pParse->hasNonstd = 1; |
| 204439 | 204947 | } |
| | @@ -204450,617 +204958,1508 @@ |
| 204450 | 204958 | return 1; |
| 204451 | 204959 | } |
| 204452 | 204960 | return 0; |
| 204453 | 204961 | } |
| 204454 | 204962 | |
| 204455 | | - |
| 204456 | | -/* Mark node i of pParse as being a child of iParent. Call recursively |
| 204457 | | -** to fill in all the descendants of node i. |
| 204458 | | -*/ |
| 204459 | | -static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ |
| 204460 | | - JsonNode *pNode = &pParse->aNode[i]; |
| 204461 | | - u32 j; |
| 204462 | | - pParse->aUp[i] = iParent; |
| 204463 | | - switch( pNode->eType ){ |
| 204464 | | - case JSON_ARRAY: { |
| 204465 | | - for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ |
| 204466 | | - jsonParseFillInParentage(pParse, i+j, i); |
| 204467 | | - } |
| 204468 | | - break; |
| 204469 | | - } |
| 204470 | | - case JSON_OBJECT: { |
| 204471 | | - for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ |
| 204472 | | - pParse->aUp[i+j] = i; |
| 204473 | | - jsonParseFillInParentage(pParse, i+j+1, i); |
| 204474 | | - } |
| 204475 | | - break; |
| 204476 | | - } |
| 204477 | | - default: { |
| 204478 | | - break; |
| 204479 | | - } |
| 204480 | | - } |
| 204481 | | -} |
| 204482 | | - |
| 204483 | | -/* |
| 204484 | | -** Compute the parentage of all nodes in a completed parse. |
| 204485 | | -*/ |
| 204486 | | -static int jsonParseFindParents(JsonParse *pParse){ |
| 204487 | | - u32 *aUp; |
| 204488 | | - assert( pParse->aUp==0 ); |
| 204489 | | - aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode ); |
| 204490 | | - if( aUp==0 ){ |
| 204491 | | - pParse->oom = 1; |
| 204492 | | - return SQLITE_NOMEM; |
| 204493 | | - } |
| 204494 | | - jsonParseFillInParentage(pParse, 0, 0); |
| 204495 | | - return SQLITE_OK; |
| 204496 | | -} |
| 204497 | | - |
| 204498 | | -/* |
| 204499 | | -** Magic number used for the JSON parse cache in sqlite3_get_auxdata() |
| 204500 | | -*/ |
| 204501 | | -#define JSON_CACHE_ID (-429938) /* First cache entry */ |
| 204502 | | -#define JSON_CACHE_SZ 4 /* Max number of cache entries */ |
| 204503 | | - |
| 204504 | | -/* |
| 204505 | | -** Obtain a complete parse of the JSON found in the pJson argument |
| 204506 | | -** |
| 204507 | | -** Use the sqlite3_get_auxdata() cache to find a preexisting parse |
| 204508 | | -** if it is available. If the cache is not available or if it |
| 204509 | | -** is no longer valid, parse the JSON again and return the new parse. |
| 204510 | | -** Also register the new parse so that it will be available for |
| 204511 | | -** future sqlite3_get_auxdata() calls. |
| 204512 | | -** |
| 204513 | | -** If an error occurs and pErrCtx!=0 then report the error on pErrCtx |
| 204514 | | -** and return NULL. |
| 204515 | | -** |
| 204516 | | -** The returned pointer (if it is not NULL) is owned by the cache in |
| 204517 | | -** most cases, not the caller. The caller does NOT need to invoke |
| 204518 | | -** jsonParseFree(), in most cases. |
| 204519 | | -** |
| 204520 | | -** Except, if an error occurs and pErrCtx==0 then return the JsonParse |
| 204521 | | -** object with JsonParse.nErr non-zero and the caller will own the JsonParse |
| 204522 | | -** object. In that case, it will be the responsibility of the caller to |
| 204523 | | -** invoke jsonParseFree(). To summarize: |
| 204524 | | -** |
| 204525 | | -** pErrCtx!=0 || p->nErr==0 ==> Return value p is owned by the |
| 204526 | | -** cache. Call does not need to |
| 204527 | | -** free it. |
| 204528 | | -** |
| 204529 | | -** pErrCtx==0 && p->nErr!=0 ==> Return value is owned by the caller |
| 204530 | | -** and so the caller must free it. |
| 204531 | | -*/ |
| 204532 | | -static JsonParse *jsonParseCached( |
| 204533 | | - sqlite3_context *pCtx, /* Context to use for cache search */ |
| 204534 | | - sqlite3_value *pJson, /* Function param containing JSON text */ |
| 204535 | | - sqlite3_context *pErrCtx, /* Write parse errors here if not NULL */ |
| 204536 | | - int bUnedited /* No prior edits allowed */ |
| 204537 | | -){ |
| 204538 | | - char *zJson = (char*)sqlite3_value_text(pJson); |
| 204539 | | - int nJson = sqlite3_value_bytes(pJson); |
| 204540 | | - JsonParse *p; |
| 204541 | | - JsonParse *pMatch = 0; |
| 204542 | | - int iKey; |
| 204543 | | - int iMinKey = 0; |
| 204544 | | - u32 iMinHold = 0xffffffff; |
| 204545 | | - u32 iMaxHold = 0; |
| 204546 | | - int bJsonRCStr; |
| 204547 | | - |
| 204548 | | - if( zJson==0 ) return 0; |
| 204549 | | - for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){ |
| 204550 | | - p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey); |
| 204551 | | - if( p==0 ){ |
| 204552 | | - iMinKey = iKey; |
| 204553 | | - break; |
| 204554 | | - } |
| 204555 | | - if( pMatch==0 |
| 204556 | | - && p->nJson==nJson |
| 204557 | | - && (p->hasMod==0 || bUnedited==0) |
| 204558 | | - && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0) |
| 204559 | | - ){ |
| 204560 | | - p->nErr = 0; |
| 204561 | | - p->useMod = 0; |
| 204562 | | - pMatch = p; |
| 204563 | | - }else |
| 204564 | | - if( pMatch==0 |
| 204565 | | - && p->zAlt!=0 |
| 204566 | | - && bUnedited==0 |
| 204567 | | - && p->nAlt==nJson |
| 204568 | | - && memcmp(p->zAlt, zJson, nJson)==0 |
| 204569 | | - ){ |
| 204570 | | - p->nErr = 0; |
| 204571 | | - p->useMod = 1; |
| 204572 | | - pMatch = p; |
| 204573 | | - }else if( p->iHold<iMinHold ){ |
| 204574 | | - iMinHold = p->iHold; |
| 204575 | | - iMinKey = iKey; |
| 204576 | | - } |
| 204577 | | - if( p->iHold>iMaxHold ){ |
| 204578 | | - iMaxHold = p->iHold; |
| 204579 | | - } |
| 204580 | | - } |
| 204581 | | - if( pMatch ){ |
| 204582 | | - /* The input JSON text was found in the cache. Use the preexisting |
| 204583 | | - ** parse of this JSON */ |
| 204584 | | - pMatch->nErr = 0; |
| 204585 | | - pMatch->iHold = iMaxHold+1; |
| 204586 | | - assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */ |
| 204587 | | - return pMatch; |
| 204588 | | - } |
| 204589 | | - |
| 204590 | | - /* The input JSON was not found anywhere in the cache. We will need |
| 204591 | | - ** to parse it ourselves and generate a new JsonParse object. |
| 204592 | | - */ |
| 204593 | | - bJsonRCStr = sqlite3ValueIsOfClass(pJson,sqlite3RCStrUnref); |
| 204594 | | - p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) ); |
| 204595 | | - if( p==0 ){ |
| 204596 | | - sqlite3_result_error_nomem(pCtx); |
| 204597 | | - return 0; |
| 204598 | | - } |
| 204599 | | - memset(p, 0, sizeof(*p)); |
| 204600 | | - if( bJsonRCStr ){ |
| 204601 | | - p->zJson = sqlite3RCStrRef(zJson); |
| 204602 | | - p->bJsonIsRCStr = 1; |
| 204603 | | - }else{ |
| 204604 | | - p->zJson = (char*)&p[1]; |
| 204605 | | - memcpy(p->zJson, zJson, nJson+1); |
| 204606 | | - } |
| 204607 | | - p->nJPRef = 1; |
| 204608 | | - if( jsonParse(p, pErrCtx) ){ |
| 204609 | | - if( pErrCtx==0 ){ |
| 204610 | | - p->nErr = 1; |
| 204611 | | - assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */ |
| 204612 | | - return p; |
| 204613 | | - } |
| 204614 | | - jsonParseFree(p); |
| 204615 | | - return 0; |
| 204616 | | - } |
| 204617 | | - p->nJson = nJson; |
| 204618 | | - p->iHold = iMaxHold+1; |
| 204619 | | - /* Transfer ownership of the new JsonParse to the cache */ |
| 204620 | | - sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, |
| 204621 | | - (void(*)(void*))jsonParseFree); |
| 204622 | | - return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); |
| 204623 | | -} |
| 204624 | | - |
| 204625 | | -/* |
| 204626 | | -** Compare the OBJECT label at pNode against zKey,nKey. Return true on |
| 204627 | | -** a match. |
| 204628 | | -*/ |
| 204629 | | -static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){ |
| 204630 | | - assert( pNode->eU==1 ); |
| 204631 | | - if( pNode->jnFlags & JNODE_RAW ){ |
| 204632 | | - if( pNode->n!=nKey ) return 0; |
| 204633 | | - return strncmp(pNode->u.zJContent, zKey, nKey)==0; |
| 204634 | | - }else{ |
| 204635 | | - if( pNode->n!=nKey+2 ) return 0; |
| 204636 | | - return strncmp(pNode->u.zJContent+1, zKey, nKey)==0; |
| 204637 | | - } |
| 204638 | | -} |
| 204639 | | -static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){ |
| 204640 | | - if( p1->jnFlags & JNODE_RAW ){ |
| 204641 | | - return jsonLabelCompare(p2, p1->u.zJContent, p1->n); |
| 204642 | | - }else if( p2->jnFlags & JNODE_RAW ){ |
| 204643 | | - return jsonLabelCompare(p1, p2->u.zJContent, p2->n); |
| 204644 | | - }else{ |
| 204645 | | - return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0; |
| 204646 | | - } |
| 204647 | | -} |
| 204648 | | - |
| 204649 | | -/* forward declaration */ |
| 204650 | | -static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); |
| 204651 | | - |
| 204652 | | -/* |
| 204653 | | -** Search along zPath to find the node specified. Return a pointer |
| 204654 | | -** to that node, or NULL if zPath is malformed or if there is no such |
| 204655 | | -** node. |
| 204656 | | -** |
| 204657 | | -** If pApnd!=0, then try to append new nodes to complete zPath if it is |
| 204658 | | -** possible to do so and if no existing node corresponds to zPath. If |
| 204659 | | -** new nodes are appended *pApnd is set to 1. |
| 204660 | | -*/ |
| 204661 | | -static JsonNode *jsonLookupStep( |
| 204662 | | - JsonParse *pParse, /* The JSON to search */ |
| 204663 | | - u32 iRoot, /* Begin the search at this node */ |
| 204664 | | - const char *zPath, /* The path to search */ |
| 204665 | | - int *pApnd, /* Append nodes to complete path if not NULL */ |
| 204666 | | - const char **pzErr /* Make *pzErr point to any syntax error in zPath */ |
| 204667 | | -){ |
| 204668 | | - u32 i, j, nKey; |
| 204669 | | - const char *zKey; |
| 204670 | | - JsonNode *pRoot; |
| 204671 | | - if( pParse->oom ) return 0; |
| 204672 | | - pRoot = &pParse->aNode[iRoot]; |
| 204673 | | - if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){ |
| 204674 | | - while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){ |
| 204675 | | - u32 idx = (u32)(pRoot - pParse->aNode); |
| 204676 | | - i = pParse->iSubst; |
| 204677 | | - while( 1 /*exit-by-break*/ ){ |
| 204678 | | - assert( i<pParse->nNode ); |
| 204679 | | - assert( pParse->aNode[i].eType==JSON_SUBST ); |
| 204680 | | - assert( pParse->aNode[i].eU==4 ); |
| 204681 | | - assert( pParse->aNode[i].u.iPrev<i ); |
| 204682 | | - if( pParse->aNode[i].n==idx ){ |
| 204683 | | - pRoot = &pParse->aNode[i+1]; |
| 204684 | | - iRoot = i+1; |
| 204685 | | - break; |
| 204686 | | - } |
| 204687 | | - i = pParse->aNode[i].u.iPrev; |
| 204688 | | - } |
| 204689 | | - } |
| 204690 | | - if( pRoot->jnFlags & JNODE_REMOVE ){ |
| 204691 | | - return 0; |
| 204692 | | - } |
| 204693 | | - } |
| 204694 | | - if( zPath[0]==0 ) return pRoot; |
| 204695 | | - if( zPath[0]=='.' ){ |
| 204696 | | - if( pRoot->eType!=JSON_OBJECT ) return 0; |
| 204963 | +/* |
| 204964 | +** The input string pStr is a well-formed JSON text string. Convert |
| 204965 | +** this into the JSONB format and make it the return value of the |
| 204966 | +** SQL function. |
| 204967 | +*/ |
| 204968 | +static void jsonReturnStringAsBlob(JsonString *pStr){ |
| 204969 | + JsonParse px; |
| 204970 | + memset(&px, 0, sizeof(px)); |
| 204971 | + jsonStringTerminate(pStr); |
| 204972 | + px.zJson = pStr->zBuf; |
| 204973 | + px.nJson = pStr->nUsed; |
| 204974 | + (void)jsonXlateTextToBlob(&px, 0); |
| 204975 | + if( px.oom ){ |
| 204976 | + sqlite3_free(px.aBlob); |
| 204977 | + sqlite3_result_error_nomem(pStr->pCtx); |
| 204978 | + }else{ |
| 204979 | + assert( px.nBlobAlloc>0 ); |
| 204980 | + assert( !px.bReadOnly ); |
| 204981 | + sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, sqlite3_free); |
| 204982 | + } |
| 204983 | +} |
| 204984 | + |
| 204985 | +/* The byte at index i is a node type-code. This routine |
| 204986 | +** determines the payload size for that node and writes that |
| 204987 | +** payload size in to *pSz. It returns the offset from i to the |
| 204988 | +** beginning of the payload. Return 0 on error. |
| 204989 | +*/ |
| 204990 | +static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ |
| 204991 | + u8 x; |
| 204992 | + u32 sz; |
| 204993 | + u32 n; |
| 204994 | + if( NEVER(i>pParse->nBlob) ){ |
| 204995 | + *pSz = 0; |
| 204996 | + return 0; |
| 204997 | + } |
| 204998 | + x = pParse->aBlob[i]>>4; |
| 204999 | + if( x<=11 ){ |
| 205000 | + sz = x; |
| 205001 | + n = 1; |
| 205002 | + }else if( x==12 ){ |
| 205003 | + if( i+1>=pParse->nBlob ){ |
| 205004 | + *pSz = 0; |
| 205005 | + return 0; |
| 205006 | + } |
| 205007 | + sz = pParse->aBlob[i+1]; |
| 205008 | + n = 2; |
| 205009 | + }else if( x==13 ){ |
| 205010 | + if( i+2>=pParse->nBlob ){ |
| 205011 | + *pSz = 0; |
| 205012 | + return 0; |
| 205013 | + } |
| 205014 | + sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2]; |
| 205015 | + n = 3; |
| 205016 | + }else if( x==14 ){ |
| 205017 | + if( i+4>=pParse->nBlob ){ |
| 205018 | + *pSz = 0; |
| 205019 | + return 0; |
| 205020 | + } |
| 205021 | + sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) + |
| 205022 | + (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4]; |
| 205023 | + n = 5; |
| 205024 | + }else{ |
| 205025 | + if( i+8>=pParse->nBlob |
| 205026 | + || pParse->aBlob[i+1]!=0 |
| 205027 | + || pParse->aBlob[i+2]!=0 |
| 205028 | + || pParse->aBlob[i+3]!=0 |
| 205029 | + || pParse->aBlob[i+4]!=0 |
| 205030 | + ){ |
| 205031 | + *pSz = 0; |
| 205032 | + return 0; |
| 205033 | + } |
| 205034 | + sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + |
| 205035 | + (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; |
| 205036 | + n = 9; |
| 205037 | + } |
| 205038 | + if( i+sz+n > pParse->nBlob |
| 205039 | + && i+sz+n > pParse->nBlob-pParse->delta |
| 205040 | + ){ |
| 205041 | + sz = 0; |
| 205042 | + n = 0; |
| 205043 | + } |
| 205044 | + *pSz = sz; |
| 205045 | + return n; |
| 205046 | +} |
| 205047 | + |
| 205048 | + |
| 205049 | +/* |
| 205050 | +** Translate the binary JSONB representation of JSON beginning at |
| 205051 | +** pParse->aBlob[i] into a JSON text string. Append the JSON |
| 205052 | +** text onto the end of pOut. Return the index in pParse->aBlob[] |
| 205053 | +** of the first byte past the end of the element that is translated. |
| 205054 | +** |
| 205055 | +** If an error is detected in the BLOB input, the pOut->eErr flag |
| 205056 | +** might get set to JSTRING_MALFORMED. But not all BLOB input errors |
| 205057 | +** are detected. So a malformed JSONB input might either result |
| 205058 | +** in an error, or in incorrect JSON. |
| 205059 | +** |
| 205060 | +** The pOut->eErr JSTRING_OOM flag is set on a OOM. |
| 205061 | +*/ |
| 205062 | +static u32 jsonXlateBlobToText( |
| 205063 | + const JsonParse *pParse, /* the complete parse of the JSON */ |
| 205064 | + u32 i, /* Start rendering at this index */ |
| 205065 | + JsonString *pOut /* Write JSON here */ |
| 205066 | +){ |
| 205067 | + u32 sz, n, j, iEnd; |
| 205068 | + |
| 205069 | + n = jsonbPayloadSize(pParse, i, &sz); |
| 205070 | + if( n==0 ){ |
| 205071 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205072 | + return pParse->nBlob+1; |
| 205073 | + } |
| 205074 | + switch( pParse->aBlob[i] & 0x0f ){ |
| 205075 | + case JSONB_NULL: { |
| 205076 | + jsonAppendRawNZ(pOut, "null", 4); |
| 205077 | + return i+1; |
| 205078 | + } |
| 205079 | + case JSONB_TRUE: { |
| 205080 | + jsonAppendRawNZ(pOut, "true", 4); |
| 205081 | + return i+1; |
| 205082 | + } |
| 205083 | + case JSONB_FALSE: { |
| 205084 | + jsonAppendRawNZ(pOut, "false", 5); |
| 205085 | + return i+1; |
| 205086 | + } |
| 205087 | + case JSONB_INT: |
| 205088 | + case JSONB_FLOAT: { |
| 205089 | + jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); |
| 205090 | + break; |
| 205091 | + } |
| 205092 | + case JSONB_INT5: { /* Integer literal in hexadecimal notation */ |
| 205093 | + u32 k = 2; |
| 205094 | + sqlite3_uint64 u = 0; |
| 205095 | + const char *zIn = (const char*)&pParse->aBlob[i+n]; |
| 205096 | + int bOverflow = 0; |
| 205097 | + if( zIn[0]=='-' ){ |
| 205098 | + jsonAppendChar(pOut, '-'); |
| 205099 | + k++; |
| 205100 | + }else if( zIn[0]=='+' ){ |
| 205101 | + k++; |
| 205102 | + } |
| 205103 | + for(; k<sz; k++){ |
| 205104 | + if( !sqlite3Isxdigit(zIn[k]) ){ |
| 205105 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205106 | + break; |
| 205107 | + }else if( (u>>60)!=0 ){ |
| 205108 | + bOverflow = 1; |
| 205109 | + }else{ |
| 205110 | + u = u*16 + sqlite3HexToInt(zIn[k]); |
| 205111 | + } |
| 205112 | + } |
| 205113 | + jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u); |
| 205114 | + break; |
| 205115 | + } |
| 205116 | + case JSONB_FLOAT5: { /* Float literal missing digits beside "." */ |
| 205117 | + u32 k = 0; |
| 205118 | + const char *zIn = (const char*)&pParse->aBlob[i+n]; |
| 205119 | + if( zIn[0]=='-' ){ |
| 205120 | + jsonAppendChar(pOut, '-'); |
| 205121 | + k++; |
| 205122 | + } |
| 205123 | + if( zIn[k]=='.' ){ |
| 205124 | + jsonAppendChar(pOut, '0'); |
| 205125 | + } |
| 205126 | + for(; k<sz; k++){ |
| 205127 | + jsonAppendChar(pOut, zIn[k]); |
| 205128 | + if( zIn[k]=='.' && (k+1==sz || !sqlite3Isdigit(zIn[k+1])) ){ |
| 205129 | + jsonAppendChar(pOut, '0'); |
| 205130 | + } |
| 205131 | + } |
| 205132 | + break; |
| 205133 | + } |
| 205134 | + case JSONB_TEXT: |
| 205135 | + case JSONB_TEXTJ: { |
| 205136 | + jsonAppendChar(pOut, '"'); |
| 205137 | + jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz); |
| 205138 | + jsonAppendChar(pOut, '"'); |
| 205139 | + break; |
| 205140 | + } |
| 205141 | + case JSONB_TEXT5: { |
| 205142 | + const char *zIn; |
| 205143 | + u32 k; |
| 205144 | + u32 sz2 = sz; |
| 205145 | + zIn = (const char*)&pParse->aBlob[i+n]; |
| 205146 | + jsonAppendChar(pOut, '"'); |
| 205147 | + while( sz2>0 ){ |
| 205148 | + for(k=0; k<sz2 && zIn[k]!='\\' && zIn[k]!='"'; k++){} |
| 205149 | + if( k>0 ){ |
| 205150 | + jsonAppendRawNZ(pOut, zIn, k); |
| 205151 | + if( k>=sz2 ){ |
| 205152 | + break; |
| 205153 | + } |
| 205154 | + zIn += k; |
| 205155 | + sz2 -= k; |
| 205156 | + } |
| 205157 | + if( zIn[0]=='"' ){ |
| 205158 | + jsonAppendRawNZ(pOut, "\\\"", 2); |
| 205159 | + zIn++; |
| 205160 | + sz2--; |
| 205161 | + continue; |
| 205162 | + } |
| 205163 | + assert( zIn[0]=='\\' ); |
| 205164 | + assert( sz2>=1 ); |
| 205165 | + if( sz2<2 ){ |
| 205166 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205167 | + break; |
| 205168 | + } |
| 205169 | + switch( (u8)zIn[1] ){ |
| 205170 | + case '\'': |
| 205171 | + jsonAppendChar(pOut, '\''); |
| 205172 | + break; |
| 205173 | + case 'v': |
| 205174 | + jsonAppendRawNZ(pOut, "\\u0009", 6); |
| 205175 | + break; |
| 205176 | + case 'x': |
| 205177 | + if( sz2<4 ){ |
| 205178 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205179 | + sz2 = 2; |
| 205180 | + break; |
| 205181 | + } |
| 205182 | + jsonAppendRawNZ(pOut, "\\u00", 4); |
| 205183 | + jsonAppendRawNZ(pOut, &zIn[2], 2); |
| 205184 | + zIn += 2; |
| 205185 | + sz2 -= 2; |
| 205186 | + break; |
| 205187 | + case '0': |
| 205188 | + jsonAppendRawNZ(pOut, "\\u0000", 6); |
| 205189 | + break; |
| 205190 | + case '\r': |
| 205191 | + if( sz2>2 && zIn[2]=='\n' ){ |
| 205192 | + zIn++; |
| 205193 | + sz2--; |
| 205194 | + } |
| 205195 | + break; |
| 205196 | + case '\n': |
| 205197 | + break; |
| 205198 | + case 0xe2: |
| 205199 | + /* '\' followed by either U+2028 or U+2029 is ignored as |
| 205200 | + ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29. |
| 205201 | + ** U+2029 is the same except for the last byte */ |
| 205202 | + if( sz2<4 |
| 205203 | + || 0x80!=(u8)zIn[2] |
| 205204 | + || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3]) |
| 205205 | + ){ |
| 205206 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205207 | + sz2 = 2; |
| 205208 | + break; |
| 205209 | + } |
| 205210 | + zIn += 2; |
| 205211 | + sz2 -= 2; |
| 205212 | + break; |
| 205213 | + default: |
| 205214 | + jsonAppendRawNZ(pOut, zIn, 2); |
| 205215 | + break; |
| 205216 | + } |
| 205217 | + assert( sz2>=2 ); |
| 205218 | + zIn += 2; |
| 205219 | + sz2 -= 2; |
| 205220 | + } |
| 205221 | + jsonAppendChar(pOut, '"'); |
| 205222 | + break; |
| 205223 | + } |
| 205224 | + case JSONB_TEXTRAW: { |
| 205225 | + jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz); |
| 205226 | + break; |
| 205227 | + } |
| 205228 | + case JSONB_ARRAY: { |
| 205229 | + jsonAppendChar(pOut, '['); |
| 205230 | + j = i+n; |
| 205231 | + iEnd = j+sz; |
| 205232 | + while( j<iEnd ){ |
| 205233 | + j = jsonXlateBlobToText(pParse, j, pOut); |
| 205234 | + jsonAppendChar(pOut, ','); |
| 205235 | + } |
| 205236 | + if( sz>0 ) pOut->nUsed--; |
| 205237 | + jsonAppendChar(pOut, ']'); |
| 205238 | + break; |
| 205239 | + } |
| 205240 | + case JSONB_OBJECT: { |
| 205241 | + int x = 0; |
| 205242 | + jsonAppendChar(pOut, '{'); |
| 205243 | + j = i+n; |
| 205244 | + iEnd = j+sz; |
| 205245 | + while( j<iEnd ){ |
| 205246 | + j = jsonXlateBlobToText(pParse, j, pOut); |
| 205247 | + jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); |
| 205248 | + } |
| 205249 | + if( x & 1 ) pOut->eErr |= JSTRING_MALFORMED; |
| 205250 | + if( sz>0 ) pOut->nUsed--; |
| 205251 | + jsonAppendChar(pOut, '}'); |
| 205252 | + break; |
| 205253 | + } |
| 205254 | + |
| 205255 | + default: { |
| 205256 | + pOut->eErr |= JSTRING_MALFORMED; |
| 205257 | + break; |
| 205258 | + } |
| 205259 | + } |
| 205260 | + return i+n+sz; |
| 205261 | +} |
| 205262 | + |
| 205263 | +/* Return true if the input pJson |
| 205264 | +** |
| 205265 | +** For performance reasons, this routine does not do a detailed check of the |
| 205266 | +** input BLOB to ensure that it is well-formed. Hence, false positives are |
| 205267 | +** possible. False negatives should never occur, however. |
| 205268 | +*/ |
| 205269 | +static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ |
| 205270 | + u32 sz, n; |
| 205271 | + const u8 *aBlob; |
| 205272 | + int nBlob; |
| 205273 | + JsonParse s; |
| 205274 | + if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; |
| 205275 | + aBlob = sqlite3_value_blob(pJson); |
| 205276 | + nBlob = sqlite3_value_bytes(pJson); |
| 205277 | + if( nBlob<1 ) return 0; |
| 205278 | + if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; |
| 205279 | + memset(&s, 0, sizeof(s)); |
| 205280 | + s.aBlob = (u8*)aBlob; |
| 205281 | + s.nBlob = nBlob; |
| 205282 | + n = jsonbPayloadSize(&s, 0, &sz); |
| 205283 | + if( n==0 ) return 0; |
| 205284 | + if( sz+n!=(u32)nBlob ) return 0; |
| 205285 | + if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; |
| 205286 | + return sz+n==(u32)nBlob; |
| 205287 | +} |
| 205288 | + |
| 205289 | +/* |
| 205290 | +** Given that a JSONB_ARRAY object starts at offset i, return |
| 205291 | +** the number of entries in that array. |
| 205292 | +*/ |
| 205293 | +static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ |
| 205294 | + u32 n, sz, i, iEnd; |
| 205295 | + u32 k = 0; |
| 205296 | + n = jsonbPayloadSize(pParse, iRoot, &sz); |
| 205297 | + iEnd = iRoot+n+sz; |
| 205298 | + for(i=iRoot+n; n>0 && i<iEnd; i+=sz+n, k++){ |
| 205299 | + n = jsonbPayloadSize(pParse, i, &sz); |
| 205300 | + } |
| 205301 | + return k; |
| 205302 | +} |
| 205303 | + |
| 205304 | +/* |
| 205305 | +** Edit the payload size of the element at iRoot by the amount in |
| 205306 | +** pParse->delta. |
| 205307 | +*/ |
| 205308 | +static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){ |
| 205309 | + u32 sz = 0; |
| 205310 | + u32 nBlob; |
| 205311 | + assert( pParse->delta!=0 ); |
| 205312 | + assert( pParse->nBlobAlloc >= pParse->nBlob ); |
| 205313 | + nBlob = pParse->nBlob; |
| 205314 | + pParse->nBlob = pParse->nBlobAlloc; |
| 205315 | + (void)jsonbPayloadSize(pParse, iRoot, &sz); |
| 205316 | + pParse->nBlob = nBlob; |
| 205317 | + sz += pParse->delta; |
| 205318 | + pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz); |
| 205319 | +} |
| 205320 | + |
| 205321 | +/* |
| 205322 | +** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of |
| 205323 | +** content beginning at iDel, and replacing them with nIns bytes of |
| 205324 | +** content given by aIns. |
| 205325 | +** |
| 205326 | +** nDel may be zero, in which case no bytes are removed. But iDel is |
| 205327 | +** still important as new bytes will be insert beginning at iDel. |
| 205328 | +** |
| 205329 | +** aIns may be zero, in which case space is created to hold nIns bytes |
| 205330 | +** beginning at iDel, but that space is uninitialized. |
| 205331 | +** |
| 205332 | +** Set pParse->oom if an OOM occurs. |
| 205333 | +*/ |
| 205334 | +static void jsonBlobEdit( |
| 205335 | + JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */ |
| 205336 | + u32 iDel, /* First byte to be removed */ |
| 205337 | + u32 nDel, /* Number of bytes to remove */ |
| 205338 | + const u8 *aIns, /* Content to insert */ |
| 205339 | + u32 nIns /* Bytes of content to insert */ |
| 205340 | +){ |
| 205341 | + i64 d = (i64)nIns - (i64)nDel; |
| 205342 | + if( d!=0 ){ |
| 205343 | + if( pParse->nBlob + d > pParse->nBlobAlloc ){ |
| 205344 | + jsonBlobExpand(pParse, pParse->nBlob+d); |
| 205345 | + if( pParse->oom ) return; |
| 205346 | + } |
| 205347 | + memmove(&pParse->aBlob[iDel+nIns], |
| 205348 | + &pParse->aBlob[iDel+nDel], |
| 205349 | + pParse->nBlob - (iDel+nDel)); |
| 205350 | + pParse->nBlob += d; |
| 205351 | + pParse->delta += d; |
| 205352 | + } |
| 205353 | + if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns); |
| 205354 | +} |
| 205355 | + |
| 205356 | +/* |
| 205357 | +** Return the number of escaped newlines to be ignored. |
| 205358 | +** An escaped newline is a one of the following byte sequences: |
| 205359 | +** |
| 205360 | +** 0x5c 0x0a |
| 205361 | +** 0x5c 0x0d |
| 205362 | +** 0x5c 0x0d 0x0a |
| 205363 | +** 0x5c 0xe2 0x80 0xa8 |
| 205364 | +** 0x5c 0xe2 0x80 0xa9 |
| 205365 | +*/ |
| 205366 | +static u32 jsonBytesToBypass(const char *z, u32 n){ |
| 205367 | + u32 i = 0; |
| 205368 | + while( i+1<n ){ |
| 205369 | + if( z[i]!='\\' ) return i; |
| 205370 | + if( z[i+1]=='\n' ){ |
| 205371 | + i += 2; |
| 205372 | + continue; |
| 205373 | + } |
| 205374 | + if( z[i+1]=='\r' ){ |
| 205375 | + if( i+2<n && z[i+2]=='\n' ){ |
| 205376 | + i += 3; |
| 205377 | + }else{ |
| 205378 | + i += 2; |
| 205379 | + } |
| 205380 | + continue; |
| 205381 | + } |
| 205382 | + if( 0xe2==(u8)z[i+1] |
| 205383 | + && i+3<n |
| 205384 | + && 0x80==(u8)z[i+2] |
| 205385 | + && (0xa8==(u8)z[i+3] || 0xa9==(u8)z[i+3]) |
| 205386 | + ){ |
| 205387 | + i += 4; |
| 205388 | + continue; |
| 205389 | + } |
| 205390 | + break; |
| 205391 | + } |
| 205392 | + return i; |
| 205393 | +} |
| 205394 | + |
| 205395 | +/* |
| 205396 | +** Input z[0..n] defines JSON escape sequence including the leading '\\'. |
| 205397 | +** Decode that escape sequence into a single character. Write that |
| 205398 | +** character into *piOut. Return the number of bytes in the escape sequence. |
| 205399 | +*/ |
| 205400 | +static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){ |
| 205401 | + assert( n>0 ); |
| 205402 | + assert( z[0]=='\\' ); |
| 205403 | + if( n<2 ){ |
| 205404 | + *piOut = 0xFFFD; |
| 205405 | + return n; |
| 205406 | + } |
| 205407 | + switch( (u8)z[1] ){ |
| 205408 | + case 'u': { |
| 205409 | + u32 v, vlo; |
| 205410 | + if( n<6 ){ |
| 205411 | + *piOut = 0xFFFD; |
| 205412 | + return n; |
| 205413 | + } |
| 205414 | + v = jsonHexToInt4(&z[2]); |
| 205415 | + if( (v & 0xfc00)==0xd800 |
| 205416 | + && n>=12 |
| 205417 | + && z[6]=='\\' |
| 205418 | + && z[7]=='u' |
| 205419 | + && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00 |
| 205420 | + ){ |
| 205421 | + *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000; |
| 205422 | + return 12; |
| 205423 | + }else{ |
| 205424 | + *piOut = v; |
| 205425 | + return 6; |
| 205426 | + } |
| 205427 | + } |
| 205428 | + case 'b': { *piOut = '\b'; return 2; } |
| 205429 | + case 'f': { *piOut = '\f'; return 2; } |
| 205430 | + case 'n': { *piOut = '\n'; return 2; } |
| 205431 | + case 'r': { *piOut = '\r'; return 2; } |
| 205432 | + case 't': { *piOut = '\t'; return 2; } |
| 205433 | + case 'v': { *piOut = '\v'; return 2; } |
| 205434 | + case '0': { *piOut = 0; return 2; } |
| 205435 | + case '\'': |
| 205436 | + case '"': |
| 205437 | + case '/': |
| 205438 | + case '\\':{ *piOut = z[1]; return 2; } |
| 205439 | + case 'x': { |
| 205440 | + if( n<4 ){ |
| 205441 | + *piOut = 0xFFFD; |
| 205442 | + return n; |
| 205443 | + } |
| 205444 | + *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]); |
| 205445 | + return 4; |
| 205446 | + } |
| 205447 | + case 0xe2: |
| 205448 | + case '\r': |
| 205449 | + case '\n': { |
| 205450 | + u32 nSkip = jsonBytesToBypass(z, n); |
| 205451 | + if( nSkip==0 ){ |
| 205452 | + *piOut = 0xFFFD; |
| 205453 | + return n; |
| 205454 | + }else if( nSkip==n ){ |
| 205455 | + *piOut = 0; |
| 205456 | + return n; |
| 205457 | + }else if( z[nSkip]=='\\' ){ |
| 205458 | + return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut); |
| 205459 | + }else{ |
| 205460 | + int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut); |
| 205461 | + return nSkip + sz; |
| 205462 | + } |
| 205463 | + } |
| 205464 | + default: { |
| 205465 | + *piOut = 0xFFFD; |
| 205466 | + return 2; |
| 205467 | + } |
| 205468 | + } |
| 205469 | +} |
| 205470 | + |
| 205471 | + |
| 205472 | +/* |
| 205473 | +** Compare two object labels. Return 1 if they are equal and |
| 205474 | +** 0 if they differ. |
| 205475 | +** |
| 205476 | +** In this version, we know that one or the other or both of the |
| 205477 | +** two comparands contains an escape sequence. |
| 205478 | +*/ |
| 205479 | +static SQLITE_NOINLINE int jsonLabelCompareEscaped( |
| 205480 | + const char *zLeft, /* The left label */ |
| 205481 | + u32 nLeft, /* Size of the left label in bytes */ |
| 205482 | + int rawLeft, /* True if zLeft contains no escapes */ |
| 205483 | + const char *zRight, /* The right label */ |
| 205484 | + u32 nRight, /* Size of the right label in bytes */ |
| 205485 | + int rawRight /* True if zRight is escape-free */ |
| 205486 | +){ |
| 205487 | + u32 cLeft, cRight; |
| 205488 | + assert( rawLeft==0 || rawRight==0 ); |
| 205489 | + while( 1 /*exit-by-return*/ ){ |
| 205490 | + if( nLeft==0 ){ |
| 205491 | + cLeft = 0; |
| 205492 | + }else if( rawLeft || zLeft[0]!='\\' ){ |
| 205493 | + cLeft = ((u8*)zLeft)[0]; |
| 205494 | + if( cLeft>=0xc0 ){ |
| 205495 | + int sz = sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft); |
| 205496 | + zLeft += sz; |
| 205497 | + nLeft -= sz; |
| 205498 | + }else{ |
| 205499 | + zLeft++; |
| 205500 | + nLeft--; |
| 205501 | + } |
| 205502 | + }else{ |
| 205503 | + u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft); |
| 205504 | + zLeft += n; |
| 205505 | + assert( n<=nLeft ); |
| 205506 | + nLeft -= n; |
| 205507 | + } |
| 205508 | + if( nRight==0 ){ |
| 205509 | + cRight = 0; |
| 205510 | + }else if( rawRight || zRight[0]!='\\' ){ |
| 205511 | + cRight = ((u8*)zRight)[0]; |
| 205512 | + if( cRight>=0xc0 ){ |
| 205513 | + int sz = sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight); |
| 205514 | + zRight += sz; |
| 205515 | + nRight -= sz; |
| 205516 | + }else{ |
| 205517 | + zRight++; |
| 205518 | + nRight--; |
| 205519 | + } |
| 205520 | + }else{ |
| 205521 | + u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight); |
| 205522 | + zRight += n; |
| 205523 | + assert( n<=nRight ); |
| 205524 | + nRight -= n; |
| 205525 | + } |
| 205526 | + if( cLeft!=cRight ) return 0; |
| 205527 | + if( cLeft==0 ) return 1; |
| 205528 | + } |
| 205529 | +} |
| 205530 | + |
| 205531 | +/* |
| 205532 | +** Compare two object labels. Return 1 if they are equal and |
| 205533 | +** 0 if they differ. Return -1 if an OOM occurs. |
| 205534 | +*/ |
| 205535 | +static int jsonLabelCompare( |
| 205536 | + const char *zLeft, /* The left label */ |
| 205537 | + u32 nLeft, /* Size of the left label in bytes */ |
| 205538 | + int rawLeft, /* True if zLeft contains no escapes */ |
| 205539 | + const char *zRight, /* The right label */ |
| 205540 | + u32 nRight, /* Size of the right label in bytes */ |
| 205541 | + int rawRight /* True if zRight is escape-free */ |
| 205542 | +){ |
| 205543 | + if( rawLeft && rawRight ){ |
| 205544 | + /* Simpliest case: Neither label contains escapes. A simple |
| 205545 | + ** memcmp() is sufficient. */ |
| 205546 | + if( nLeft!=nRight ) return 0; |
| 205547 | + return memcmp(zLeft, zRight, nLeft)==0; |
| 205548 | + }else{ |
| 205549 | + return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft, |
| 205550 | + zRight, nRight, rawRight); |
| 205551 | + } |
| 205552 | +} |
| 205553 | + |
| 205554 | +/* |
| 205555 | +** Error returns from jsonLookupStep() |
| 205556 | +*/ |
| 205557 | +#define JSON_LOOKUP_ERROR 0xffffffff |
| 205558 | +#define JSON_LOOKUP_NOTFOUND 0xfffffffe |
| 205559 | +#define JSON_LOOKUP_PATHERROR 0xfffffffd |
| 205560 | +#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR) |
| 205561 | + |
| 205562 | +/* Forward declaration */ |
| 205563 | +static u32 jsonLookupStep(JsonParse*,u32,const char*,u32); |
| 205564 | + |
| 205565 | + |
| 205566 | +/* This helper routine for jsonLookupStep() populates pIns with |
| 205567 | +** binary data that is to be inserted into pParse. |
| 205568 | +** |
| 205569 | +** In the common case, pIns just points to pParse->aIns and pParse->nIns. |
| 205570 | +** But if the zPath of the original edit operation includes path elements |
| 205571 | +** that go deeper, additional substructure must be created. |
| 205572 | +** |
| 205573 | +** For example: |
| 205574 | +** |
| 205575 | +** json_insert('{}', '$.a.b.c', 123); |
| 205576 | +** |
| 205577 | +** The search stops at '$.a' But additional substructure must be |
| 205578 | +** created for the ".b.c" part of the patch so that the final result |
| 205579 | +** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with |
| 205580 | +** the binary equivalent of {"b":{"c":123}} so that it can be inserted. |
| 205581 | +** |
| 205582 | +** The caller is responsible for resetting pIns when it has finished |
| 205583 | +** using the substructure. |
| 205584 | +*/ |
| 205585 | +static u32 jsonCreateEditSubstructure( |
| 205586 | + JsonParse *pParse, /* The original JSONB that is being edited */ |
| 205587 | + JsonParse *pIns, /* Populate this with the blob data to insert */ |
| 205588 | + const char *zTail /* Tail of the path that determins substructure */ |
| 205589 | +){ |
| 205590 | + static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT }; |
| 205591 | + int rc; |
| 205592 | + memset(pIns, 0, sizeof(*pIns)); |
| 205593 | + if( zTail[0]==0 ){ |
| 205594 | + /* No substructure. Just insert what is given in pParse. */ |
| 205595 | + pIns->aBlob = pParse->aIns; |
| 205596 | + pIns->nBlob = pParse->nIns; |
| 205597 | + rc = 0; |
| 205598 | + }else{ |
| 205599 | + /* Construct the binary substructure */ |
| 205600 | + pIns->nBlob = 1; |
| 205601 | + pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.']; |
| 205602 | + pIns->eEdit = pParse->eEdit; |
| 205603 | + pIns->nIns = pParse->nIns; |
| 205604 | + pIns->aIns = pParse->aIns; |
| 205605 | + rc = jsonLookupStep(pIns, 0, zTail, 0); |
| 205606 | + pParse->oom |= pIns->oom; |
| 205607 | + } |
| 205608 | + return rc; /* Error code only */ |
| 205609 | +} |
| 205610 | + |
| 205611 | +/* |
| 205612 | +** Search along zPath to find the Json element specified. Return an |
| 205613 | +** index into pParse->aBlob[] for the start of that element's value. |
| 205614 | +** |
| 205615 | +** If the value found by this routine is the value half of label/value pair |
| 205616 | +** within an object, then set pPath->iLabel to the start of the corresponding |
| 205617 | +** label, before returning. |
| 205618 | +** |
| 205619 | +** Return one of the JSON_LOOKUP error codes if problems are seen. |
| 205620 | +** |
| 205621 | +** This routine will also modify the blob. If pParse->eEdit is one of |
| 205622 | +** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be |
| 205623 | +** made to the selected value. If an edit is performed, then the return |
| 205624 | +** value does not necessarily point to the select element. If an edit |
| 205625 | +** is performed, the return value is only useful for detecting error |
| 205626 | +** conditions. |
| 205627 | +*/ |
| 205628 | +static u32 jsonLookupStep( |
| 205629 | + JsonParse *pParse, /* The JSON to search */ |
| 205630 | + u32 iRoot, /* Begin the search at this element of aBlob[] */ |
| 205631 | + const char *zPath, /* The path to search */ |
| 205632 | + u32 iLabel /* Label if iRoot is a value of in an object */ |
| 205633 | +){ |
| 205634 | + u32 i, j, k, nKey, sz, n, iEnd, rc; |
| 205635 | + const char *zKey; |
| 205636 | + u8 x; |
| 205637 | + |
| 205638 | + if( zPath[0]==0 ){ |
| 205639 | + if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){ |
| 205640 | + n = jsonbPayloadSize(pParse, iRoot, &sz); |
| 205641 | + sz += n; |
| 205642 | + if( pParse->eEdit==JEDIT_DEL ){ |
| 205643 | + if( iLabel>0 ){ |
| 205644 | + sz += iRoot - iLabel; |
| 205645 | + iRoot = iLabel; |
| 205646 | + } |
| 205647 | + jsonBlobEdit(pParse, iRoot, sz, 0, 0); |
| 205648 | + }else if( pParse->eEdit==JEDIT_INS ){ |
| 205649 | + /* Already exists, so json_insert() is a no-op */ |
| 205650 | + }else{ |
| 205651 | + /* json_set() or json_replace() */ |
| 205652 | + jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns); |
| 205653 | + } |
| 205654 | + } |
| 205655 | + pParse->iLabel = iLabel; |
| 205656 | + return iRoot; |
| 205657 | + } |
| 205658 | + if( zPath[0]=='.' ){ |
| 205659 | + int rawKey = 1; |
| 205660 | + x = pParse->aBlob[iRoot]; |
| 204697 | 205661 | zPath++; |
| 204698 | 205662 | if( zPath[0]=='"' ){ |
| 204699 | 205663 | zKey = zPath + 1; |
| 204700 | 205664 | for(i=1; zPath[i] && zPath[i]!='"'; i++){} |
| 204701 | 205665 | nKey = i-1; |
| 204702 | 205666 | if( zPath[i] ){ |
| 204703 | 205667 | i++; |
| 204704 | 205668 | }else{ |
| 204705 | | - *pzErr = zPath; |
| 204706 | | - return 0; |
| 205669 | + return JSON_LOOKUP_PATHERROR; |
| 204707 | 205670 | } |
| 204708 | 205671 | testcase( nKey==0 ); |
| 205672 | + rawKey = memchr(zKey, '\\', nKey)==0; |
| 204709 | 205673 | }else{ |
| 204710 | 205674 | zKey = zPath; |
| 204711 | 205675 | for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} |
| 204712 | 205676 | nKey = i; |
| 204713 | 205677 | if( nKey==0 ){ |
| 204714 | | - *pzErr = zPath; |
| 204715 | | - return 0; |
| 204716 | | - } |
| 204717 | | - } |
| 204718 | | - j = 1; |
| 204719 | | - for(;;){ |
| 204720 | | - while( j<=pRoot->n ){ |
| 204721 | | - if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ |
| 204722 | | - return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); |
| 204723 | | - } |
| 204724 | | - j++; |
| 204725 | | - j += jsonNodeSize(&pRoot[j]); |
| 204726 | | - } |
| 204727 | | - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; |
| 204728 | | - if( pParse->useMod==0 ) break; |
| 204729 | | - assert( pRoot->eU==2 ); |
| 204730 | | - iRoot = pRoot->u.iAppend; |
| 204731 | | - pRoot = &pParse->aNode[iRoot]; |
| 204732 | | - j = 1; |
| 204733 | | - } |
| 204734 | | - if( pApnd ){ |
| 204735 | | - u32 iStart, iLabel; |
| 204736 | | - JsonNode *pNode; |
| 204737 | | - assert( pParse->useMod ); |
| 204738 | | - iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); |
| 204739 | | - iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); |
| 204740 | | - zPath += i; |
| 204741 | | - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); |
| 204742 | | - if( pParse->oom ) return 0; |
| 204743 | | - if( pNode ){ |
| 204744 | | - pRoot = &pParse->aNode[iRoot]; |
| 204745 | | - assert( pRoot->eU==0 ); |
| 204746 | | - pRoot->u.iAppend = iStart; |
| 204747 | | - pRoot->jnFlags |= JNODE_APPEND; |
| 204748 | | - VVA( pRoot->eU = 2 ); |
| 204749 | | - pParse->aNode[iLabel].jnFlags |= JNODE_RAW; |
| 204750 | | - } |
| 204751 | | - return pNode; |
| 205678 | + return JSON_LOOKUP_PATHERROR; |
| 205679 | + } |
| 205680 | + } |
| 205681 | + if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND; |
| 205682 | + n = jsonbPayloadSize(pParse, iRoot, &sz); |
| 205683 | + j = iRoot + n; /* j is the index of a label */ |
| 205684 | + iEnd = j+sz; |
| 205685 | + while( j<iEnd ){ |
| 205686 | + int rawLabel; |
| 205687 | + const char *zLabel; |
| 205688 | + x = pParse->aBlob[j] & 0x0f; |
| 205689 | + if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return JSON_LOOKUP_ERROR; |
| 205690 | + n = jsonbPayloadSize(pParse, j, &sz); |
| 205691 | + if( n==0 ) return JSON_LOOKUP_ERROR; |
| 205692 | + k = j+n; /* k is the index of the label text */ |
| 205693 | + if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR; |
| 205694 | + zLabel = (const char*)&pParse->aBlob[k]; |
| 205695 | + rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW; |
| 205696 | + if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){ |
| 205697 | + u32 v = k+sz; /* v is the index of the value */ |
| 205698 | + if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; |
| 205699 | + n = jsonbPayloadSize(pParse, v, &sz); |
| 205700 | + if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR; |
| 205701 | + assert( j>0 ); |
| 205702 | + rc = jsonLookupStep(pParse, v, &zPath[i], j); |
| 205703 | + if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); |
| 205704 | + return rc; |
| 205705 | + } |
| 205706 | + j = k+sz; |
| 205707 | + if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR; |
| 205708 | + n = jsonbPayloadSize(pParse, j, &sz); |
| 205709 | + if( n==0 ) return JSON_LOOKUP_ERROR; |
| 205710 | + j += n+sz; |
| 205711 | + } |
| 205712 | + if( j>iEnd ) return JSON_LOOKUP_ERROR; |
| 205713 | + if( pParse->eEdit>=JEDIT_INS ){ |
| 205714 | + u32 nIns; /* Total bytes to insert (label+value) */ |
| 205715 | + JsonParse v; /* BLOB encoding of the value to be inserted */ |
| 205716 | + JsonParse ix; /* Header of the label to be inserted */ |
| 205717 | + testcase( pParse->eEdit==JEDIT_INS ); |
| 205718 | + testcase( pParse->eEdit==JEDIT_SET ); |
| 205719 | + memset(&ix, 0, sizeof(ix)); |
| 205720 | + jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0); |
| 205721 | + pParse->oom |= ix.oom; |
| 205722 | + rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]); |
| 205723 | + if( !JSON_LOOKUP_ISERROR(rc) |
| 205724 | + && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob) |
| 205725 | + ){ |
| 205726 | + assert( !pParse->oom ); |
| 205727 | + nIns = ix.nBlob + nKey + v.nBlob; |
| 205728 | + jsonBlobEdit(pParse, j, 0, 0, nIns); |
| 205729 | + if( !pParse->oom ){ |
| 205730 | + assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */ |
| 205731 | + assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */ |
| 205732 | + memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob); |
| 205733 | + k = j + ix.nBlob; |
| 205734 | + memcpy(&pParse->aBlob[k], zKey, nKey); |
| 205735 | + k += nKey; |
| 205736 | + memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob); |
| 205737 | + if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot); |
| 205738 | + } |
| 205739 | + } |
| 205740 | + jsonParseReset(&v); |
| 205741 | + jsonParseReset(&ix); |
| 205742 | + return rc; |
| 204752 | 205743 | } |
| 204753 | 205744 | }else if( zPath[0]=='[' ){ |
| 204754 | | - i = 0; |
| 204755 | | - j = 1; |
| 204756 | | - while( sqlite3Isdigit(zPath[j]) ){ |
| 204757 | | - i = i*10 + zPath[j] - '0'; |
| 204758 | | - j++; |
| 204759 | | - } |
| 204760 | | - if( j<2 || zPath[j]!=']' ){ |
| 204761 | | - if( zPath[1]=='#' ){ |
| 204762 | | - JsonNode *pBase = pRoot; |
| 204763 | | - int iBase = iRoot; |
| 204764 | | - if( pRoot->eType!=JSON_ARRAY ) return 0; |
| 204765 | | - for(;;){ |
| 204766 | | - while( j<=pBase->n ){ |
| 204767 | | - if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++; |
| 204768 | | - j += jsonNodeSize(&pBase[j]); |
| 204769 | | - } |
| 204770 | | - if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; |
| 204771 | | - if( pParse->useMod==0 ) break; |
| 204772 | | - assert( pBase->eU==2 ); |
| 204773 | | - iBase = pBase->u.iAppend; |
| 204774 | | - pBase = &pParse->aNode[iBase]; |
| 204775 | | - j = 1; |
| 204776 | | - } |
| 204777 | | - j = 2; |
| 204778 | | - if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ |
| 204779 | | - unsigned int x = 0; |
| 204780 | | - j = 3; |
| 204781 | | - do{ |
| 204782 | | - x = x*10 + zPath[j] - '0'; |
| 204783 | | - j++; |
| 204784 | | - }while( sqlite3Isdigit(zPath[j]) ); |
| 204785 | | - if( x>i ) return 0; |
| 204786 | | - i -= x; |
| 204787 | | - } |
| 204788 | | - if( zPath[j]!=']' ){ |
| 204789 | | - *pzErr = zPath; |
| 204790 | | - return 0; |
| 204791 | | - } |
| 204792 | | - }else{ |
| 204793 | | - *pzErr = zPath; |
| 204794 | | - return 0; |
| 204795 | | - } |
| 204796 | | - } |
| 204797 | | - if( pRoot->eType!=JSON_ARRAY ) return 0; |
| 204798 | | - zPath += j + 1; |
| 204799 | | - j = 1; |
| 204800 | | - for(;;){ |
| 204801 | | - while( j<=pRoot->n |
| 204802 | | - && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod)) |
| 204803 | | - ){ |
| 204804 | | - if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--; |
| 204805 | | - j += jsonNodeSize(&pRoot[j]); |
| 204806 | | - } |
| 204807 | | - if( i==0 && j<=pRoot->n ) break; |
| 204808 | | - if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; |
| 204809 | | - if( pParse->useMod==0 ) break; |
| 204810 | | - assert( pRoot->eU==2 ); |
| 204811 | | - iRoot = pRoot->u.iAppend; |
| 204812 | | - pRoot = &pParse->aNode[iRoot]; |
| 204813 | | - j = 1; |
| 204814 | | - } |
| 204815 | | - if( j<=pRoot->n ){ |
| 204816 | | - return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr); |
| 204817 | | - } |
| 204818 | | - if( i==0 && pApnd ){ |
| 204819 | | - u32 iStart; |
| 204820 | | - JsonNode *pNode; |
| 204821 | | - assert( pParse->useMod ); |
| 204822 | | - iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); |
| 204823 | | - pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); |
| 204824 | | - if( pParse->oom ) return 0; |
| 204825 | | - if( pNode ){ |
| 204826 | | - pRoot = &pParse->aNode[iRoot]; |
| 204827 | | - assert( pRoot->eU==0 ); |
| 204828 | | - pRoot->u.iAppend = iStart; |
| 204829 | | - pRoot->jnFlags |= JNODE_APPEND; |
| 204830 | | - VVA( pRoot->eU = 2 ); |
| 204831 | | - } |
| 204832 | | - return pNode; |
| 204833 | | - } |
| 204834 | | - }else{ |
| 204835 | | - *pzErr = zPath; |
| 204836 | | - } |
| 204837 | | - return 0; |
| 204838 | | -} |
| 204839 | | - |
| 204840 | | -/* |
| 204841 | | -** Append content to pParse that will complete zPath. Return a pointer |
| 204842 | | -** to the inserted node, or return NULL if the append fails. |
| 204843 | | -*/ |
| 204844 | | -static JsonNode *jsonLookupAppend( |
| 204845 | | - JsonParse *pParse, /* Append content to the JSON parse */ |
| 204846 | | - const char *zPath, /* Description of content to append */ |
| 204847 | | - int *pApnd, /* Set this flag to 1 */ |
| 204848 | | - const char **pzErr /* Make this point to any syntax error */ |
| 204849 | | -){ |
| 204850 | | - *pApnd = 1; |
| 204851 | | - if( zPath[0]==0 ){ |
| 204852 | | - jsonParseAddNode(pParse, JSON_NULL, 0, 0); |
| 204853 | | - return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; |
| 204854 | | - } |
| 204855 | | - if( zPath[0]=='.' ){ |
| 204856 | | - jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); |
| 204857 | | - }else if( strncmp(zPath,"[0]",3)==0 ){ |
| 204858 | | - jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); |
| 204859 | | - }else{ |
| 204860 | | - return 0; |
| 204861 | | - } |
| 204862 | | - if( pParse->oom ) return 0; |
| 204863 | | - return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); |
| 204864 | | -} |
| 204865 | | - |
| 204866 | | -/* |
| 204867 | | -** Return the text of a syntax error message on a JSON path. Space is |
| 204868 | | -** obtained from sqlite3_malloc(). |
| 204869 | | -*/ |
| 204870 | | -static char *jsonPathSyntaxError(const char *zErr){ |
| 204871 | | - return sqlite3_mprintf("JSON path error near '%q'", zErr); |
| 204872 | | -} |
| 204873 | | - |
| 204874 | | -/* |
| 204875 | | -** Do a node lookup using zPath. Return a pointer to the node on success. |
| 204876 | | -** Return NULL if not found or if there is an error. |
| 204877 | | -** |
| 204878 | | -** On an error, write an error message into pCtx and increment the |
| 204879 | | -** pParse->nErr counter. |
| 204880 | | -** |
| 204881 | | -** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if |
| 204882 | | -** nodes are appended. |
| 204883 | | -*/ |
| 204884 | | -static JsonNode *jsonLookup( |
| 204885 | | - JsonParse *pParse, /* The JSON to search */ |
| 204886 | | - const char *zPath, /* The path to search */ |
| 204887 | | - int *pApnd, /* Append nodes to complete path if not NULL */ |
| 204888 | | - sqlite3_context *pCtx /* Report errors here, if not NULL */ |
| 204889 | | -){ |
| 204890 | | - const char *zErr = 0; |
| 204891 | | - JsonNode *pNode = 0; |
| 204892 | | - char *zMsg; |
| 204893 | | - |
| 204894 | | - if( zPath==0 ) return 0; |
| 204895 | | - if( zPath[0]!='$' ){ |
| 204896 | | - zErr = zPath; |
| 204897 | | - goto lookup_err; |
| 204898 | | - } |
| 204899 | | - zPath++; |
| 204900 | | - pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); |
| 204901 | | - if( zErr==0 ) return pNode; |
| 204902 | | - |
| 204903 | | -lookup_err: |
| 204904 | | - pParse->nErr++; |
| 204905 | | - assert( zErr!=0 && pCtx!=0 ); |
| 204906 | | - zMsg = jsonPathSyntaxError(zErr); |
| 204907 | | - if( zMsg ){ |
| 204908 | | - sqlite3_result_error(pCtx, zMsg, -1); |
| 204909 | | - sqlite3_free(zMsg); |
| 204910 | | - }else{ |
| 204911 | | - sqlite3_result_error_nomem(pCtx); |
| 204912 | | - } |
| 204913 | | - return 0; |
| 204914 | | -} |
| 204915 | | - |
| 204916 | | - |
| 204917 | | -/* |
| 204918 | | -** Report the wrong number of arguments for json_insert(), json_replace() |
| 204919 | | -** or json_set(). |
| 204920 | | -*/ |
| 204921 | | -static void jsonWrongNumArgs( |
| 204922 | | - sqlite3_context *pCtx, |
| 204923 | | - const char *zFuncName |
| 204924 | | -){ |
| 204925 | | - char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", |
| 204926 | | - zFuncName); |
| 204927 | | - sqlite3_result_error(pCtx, zMsg, -1); |
| 204928 | | - sqlite3_free(zMsg); |
| 204929 | | -} |
| 204930 | | - |
| 204931 | | -/* |
| 204932 | | -** Mark all NULL entries in the Object passed in as JNODE_REMOVE. |
| 204933 | | -*/ |
| 204934 | | -static void jsonRemoveAllNulls(JsonNode *pNode){ |
| 204935 | | - int i, n; |
| 204936 | | - assert( pNode->eType==JSON_OBJECT ); |
| 204937 | | - n = pNode->n; |
| 204938 | | - for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ |
| 204939 | | - switch( pNode[i].eType ){ |
| 204940 | | - case JSON_NULL: |
| 204941 | | - pNode[i].jnFlags |= JNODE_REMOVE; |
| 204942 | | - break; |
| 204943 | | - case JSON_OBJECT: |
| 204944 | | - jsonRemoveAllNulls(&pNode[i]); |
| 204945 | | - break; |
| 204946 | | - } |
| 204947 | | - } |
| 204948 | | -} |
| 204949 | | - |
| 205745 | + x = pParse->aBlob[iRoot] & 0x0f; |
| 205746 | + if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; |
| 205747 | + n = jsonbPayloadSize(pParse, iRoot, &sz); |
| 205748 | + k = 0; |
| 205749 | + i = 1; |
| 205750 | + while( sqlite3Isdigit(zPath[i]) ){ |
| 205751 | + k = k*10 + zPath[i] - '0'; |
| 205752 | + i++; |
| 205753 | + } |
| 205754 | + if( i<2 || zPath[i]!=']' ){ |
| 205755 | + if( zPath[1]=='#' ){ |
| 205756 | + k = jsonbArrayCount(pParse, iRoot); |
| 205757 | + i = 2; |
| 205758 | + if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ |
| 205759 | + unsigned int nn = 0; |
| 205760 | + i = 3; |
| 205761 | + do{ |
| 205762 | + nn = nn*10 + zPath[i] - '0'; |
| 205763 | + i++; |
| 205764 | + }while( sqlite3Isdigit(zPath[i]) ); |
| 205765 | + if( nn>k ) return JSON_LOOKUP_NOTFOUND; |
| 205766 | + k -= nn; |
| 205767 | + } |
| 205768 | + if( zPath[i]!=']' ){ |
| 205769 | + return JSON_LOOKUP_PATHERROR; |
| 205770 | + } |
| 205771 | + }else{ |
| 205772 | + return JSON_LOOKUP_PATHERROR; |
| 205773 | + } |
| 205774 | + } |
| 205775 | + j = iRoot+n; |
| 205776 | + iEnd = j+sz; |
| 205777 | + while( j<iEnd ){ |
| 205778 | + if( k==0 ){ |
| 205779 | + rc = jsonLookupStep(pParse, j, &zPath[i+1], 0); |
| 205780 | + if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); |
| 205781 | + return rc; |
| 205782 | + } |
| 205783 | + k--; |
| 205784 | + n = jsonbPayloadSize(pParse, j, &sz); |
| 205785 | + if( n==0 ) return JSON_LOOKUP_ERROR; |
| 205786 | + j += n+sz; |
| 205787 | + } |
| 205788 | + if( j>iEnd ) return JSON_LOOKUP_ERROR; |
| 205789 | + if( k>0 ) return JSON_LOOKUP_NOTFOUND; |
| 205790 | + if( pParse->eEdit>=JEDIT_INS ){ |
| 205791 | + JsonParse v; |
| 205792 | + testcase( pParse->eEdit==JEDIT_INS ); |
| 205793 | + testcase( pParse->eEdit==JEDIT_SET ); |
| 205794 | + rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]); |
| 205795 | + if( !JSON_LOOKUP_ISERROR(rc) |
| 205796 | + && jsonBlobMakeEditable(pParse, v.nBlob) |
| 205797 | + ){ |
| 205798 | + assert( !pParse->oom ); |
| 205799 | + jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob); |
| 205800 | + } |
| 205801 | + jsonParseReset(&v); |
| 205802 | + if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); |
| 205803 | + return rc; |
| 205804 | + } |
| 205805 | + }else{ |
| 205806 | + return JSON_LOOKUP_PATHERROR; |
| 205807 | + } |
| 205808 | + return JSON_LOOKUP_NOTFOUND; |
| 205809 | +} |
| 205810 | + |
| 205811 | +/* |
| 205812 | +** Convert a JSON BLOB into text and make that text the return value |
| 205813 | +** of an SQL function. |
| 205814 | +*/ |
| 205815 | +static void jsonReturnTextJsonFromBlob( |
| 205816 | + sqlite3_context *ctx, |
| 205817 | + const u8 *aBlob, |
| 205818 | + u32 nBlob |
| 205819 | +){ |
| 205820 | + JsonParse x; |
| 205821 | + JsonString s; |
| 205822 | + |
| 205823 | + if( NEVER(aBlob==0) ) return; |
| 205824 | + memset(&x, 0, sizeof(x)); |
| 205825 | + x.aBlob = (u8*)aBlob; |
| 205826 | + x.nBlob = nBlob; |
| 205827 | + jsonStringInit(&s, ctx); |
| 205828 | + jsonXlateBlobToText(&x, 0, &s); |
| 205829 | + jsonReturnString(&s, 0, 0); |
| 205830 | +} |
| 205831 | + |
| 205832 | + |
| 205833 | +/* |
| 205834 | +** Return the value of the BLOB node at index i. |
| 205835 | +** |
| 205836 | +** If the value is a primitive, return it as an SQL value. |
| 205837 | +** If the value is an array or object, return it as either |
| 205838 | +** JSON text or the BLOB encoding, depending on the JSON_B flag |
| 205839 | +** on the userdata. |
| 205840 | +*/ |
| 205841 | +static void jsonReturnFromBlob( |
| 205842 | + JsonParse *pParse, /* Complete JSON parse tree */ |
| 205843 | + u32 i, /* Index of the node */ |
| 205844 | + sqlite3_context *pCtx, /* Return value for this function */ |
| 205845 | + int textOnly /* return text JSON. Disregard user-data */ |
| 205846 | +){ |
| 205847 | + u32 n, sz; |
| 205848 | + int rc; |
| 205849 | + sqlite3 *db = sqlite3_context_db_handle(pCtx); |
| 205850 | + |
| 205851 | + n = jsonbPayloadSize(pParse, i, &sz); |
| 205852 | + if( n==0 ){ |
| 205853 | + sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 205854 | + return; |
| 205855 | + } |
| 205856 | + switch( pParse->aBlob[i] & 0x0f ){ |
| 205857 | + case JSONB_NULL: { |
| 205858 | + if( sz ) goto returnfromblob_malformed; |
| 205859 | + sqlite3_result_null(pCtx); |
| 205860 | + break; |
| 205861 | + } |
| 205862 | + case JSONB_TRUE: { |
| 205863 | + if( sz ) goto returnfromblob_malformed; |
| 205864 | + sqlite3_result_int(pCtx, 1); |
| 205865 | + break; |
| 205866 | + } |
| 205867 | + case JSONB_FALSE: { |
| 205868 | + if( sz ) goto returnfromblob_malformed; |
| 205869 | + sqlite3_result_int(pCtx, 0); |
| 205870 | + break; |
| 205871 | + } |
| 205872 | + case JSONB_INT5: |
| 205873 | + case JSONB_INT: { |
| 205874 | + sqlite3_int64 iRes = 0; |
| 205875 | + char *z; |
| 205876 | + int bNeg = 0; |
| 205877 | + char x; |
| 205878 | + if( sz==0 ) goto returnfromblob_malformed; |
| 205879 | + x = (char)pParse->aBlob[i+n]; |
| 205880 | + if( x=='-' ){ |
| 205881 | + if( sz<2 ) goto returnfromblob_malformed; |
| 205882 | + n++; |
| 205883 | + sz--; |
| 205884 | + bNeg = 1; |
| 205885 | + } |
| 205886 | + z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); |
| 205887 | + if( z==0 ) goto returnfromblob_oom; |
| 205888 | + rc = sqlite3DecOrHexToI64(z, &iRes); |
| 205889 | + sqlite3DbFree(db, z); |
| 205890 | + if( rc==0 ){ |
| 205891 | + sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes); |
| 205892 | + }else if( rc==3 && bNeg ){ |
| 205893 | + sqlite3_result_int64(pCtx, SMALLEST_INT64); |
| 205894 | + }else if( rc==1 ){ |
| 205895 | + goto returnfromblob_malformed; |
| 205896 | + }else{ |
| 205897 | + if( bNeg ){ n--; sz++; } |
| 205898 | + goto to_double; |
| 205899 | + } |
| 205900 | + break; |
| 205901 | + } |
| 205902 | + case JSONB_FLOAT5: |
| 205903 | + case JSONB_FLOAT: { |
| 205904 | + double r; |
| 205905 | + char *z; |
| 205906 | + if( sz==0 ) goto returnfromblob_malformed; |
| 205907 | + to_double: |
| 205908 | + z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); |
| 205909 | + if( z==0 ) goto returnfromblob_oom; |
| 205910 | + rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); |
| 205911 | + sqlite3DbFree(db, z); |
| 205912 | + if( rc<=0 ) goto returnfromblob_malformed; |
| 205913 | + sqlite3_result_double(pCtx, r); |
| 205914 | + break; |
| 205915 | + } |
| 205916 | + case JSONB_TEXTRAW: |
| 205917 | + case JSONB_TEXT: { |
| 205918 | + sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz, |
| 205919 | + SQLITE_TRANSIENT); |
| 205920 | + break; |
| 205921 | + } |
| 205922 | + case JSONB_TEXT5: |
| 205923 | + case JSONB_TEXTJ: { |
| 205924 | + /* Translate JSON formatted string into raw text */ |
| 205925 | + u32 iIn, iOut; |
| 205926 | + const char *z; |
| 205927 | + char *zOut; |
| 205928 | + u32 nOut = sz; |
| 205929 | + z = (const char*)&pParse->aBlob[i+n]; |
| 205930 | + zOut = sqlite3_malloc( nOut+1 ); |
| 205931 | + if( zOut==0 ) goto returnfromblob_oom; |
| 205932 | + for(iIn=iOut=0; iIn<sz; iIn++){ |
| 205933 | + char c = z[iIn]; |
| 205934 | + if( c=='\\' ){ |
| 205935 | + u32 v; |
| 205936 | + u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v); |
| 205937 | + if( v<=0x7f ){ |
| 205938 | + zOut[iOut++] = (char)v; |
| 205939 | + }else if( v==0xfffd ){ |
| 205940 | + /* Silently ignore illegal unicode */ |
| 205941 | + }else if( v<=0x7ff ){ |
| 205942 | + assert( szEscape>=2 ); |
| 205943 | + zOut[iOut++] = (char)(0xc0 | (v>>6)); |
| 205944 | + zOut[iOut++] = 0x80 | (v&0x3f); |
| 205945 | + }else if( v<0x10000 ){ |
| 205946 | + assert( szEscape>=3 ); |
| 205947 | + zOut[iOut++] = 0xe0 | (v>>12); |
| 205948 | + zOut[iOut++] = 0x80 | ((v>>6)&0x3f); |
| 205949 | + zOut[iOut++] = 0x80 | (v&0x3f); |
| 205950 | + }else{ |
| 205951 | + assert( szEscape>=4 ); |
| 205952 | + zOut[iOut++] = 0xf0 | (v>>18); |
| 205953 | + zOut[iOut++] = 0x80 | ((v>>12)&0x3f); |
| 205954 | + zOut[iOut++] = 0x80 | ((v>>6)&0x3f); |
| 205955 | + zOut[iOut++] = 0x80 | (v&0x3f); |
| 205956 | + } |
| 205957 | + iIn += szEscape - 1; |
| 205958 | + }else{ |
| 205959 | + zOut[iOut++] = c; |
| 205960 | + } |
| 205961 | + } /* end for() */ |
| 205962 | + assert( iOut<=nOut ); |
| 205963 | + zOut[iOut] = 0; |
| 205964 | + sqlite3_result_text(pCtx, zOut, iOut, sqlite3_free); |
| 205965 | + break; |
| 205966 | + } |
| 205967 | + case JSONB_ARRAY: |
| 205968 | + case JSONB_OBJECT: { |
| 205969 | + int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx)); |
| 205970 | + if( flags & JSON_BLOB ){ |
| 205971 | + sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT); |
| 205972 | + }else{ |
| 205973 | + jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n); |
| 205974 | + } |
| 205975 | + break; |
| 205976 | + } |
| 205977 | + default: { |
| 205978 | + goto returnfromblob_malformed; |
| 205979 | + } |
| 205980 | + } |
| 205981 | + return; |
| 205982 | + |
| 205983 | +returnfromblob_oom: |
| 205984 | + sqlite3_result_error_nomem(pCtx); |
| 205985 | + return; |
| 205986 | + |
| 205987 | +returnfromblob_malformed: |
| 205988 | + sqlite3_result_error(pCtx, "malformed JSON", -1); |
| 205989 | + return; |
| 205990 | +} |
| 205991 | + |
| 205992 | +/* |
| 205993 | +** pArg is a function argument that might be an SQL value or a JSON |
| 205994 | +** value. Figure out what it is and encode it as a JSONB blob. |
| 205995 | +** Return the results in pParse. |
| 205996 | +** |
| 205997 | +** pParse is uninitialized upon entry. This routine will handle the |
| 205998 | +** initialization of pParse. The result will be contained in |
| 205999 | +** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically |
| 206000 | +** allocated (if pParse->nBlobAlloc is greater than zero) in which case |
| 206001 | +** the caller is responsible for freeing the space allocated to pParse->aBlob |
| 206002 | +** when it has finished with it. Or pParse->aBlob might be a static string |
| 206003 | +** or a value obtained from sqlite3_value_blob(pArg). |
| 206004 | +** |
| 206005 | +** If the argument is a BLOB that is clearly not a JSONB, then this |
| 206006 | +** function might set an error message in ctx and return non-zero. |
| 206007 | +** It might also set an error message and return non-zero on an OOM error. |
| 206008 | +*/ |
| 206009 | +static int jsonFunctionArgToBlob( |
| 206010 | + sqlite3_context *ctx, |
| 206011 | + sqlite3_value *pArg, |
| 206012 | + JsonParse *pParse |
| 206013 | +){ |
| 206014 | + int eType = sqlite3_value_type(pArg); |
| 206015 | + static u8 aNull[] = { 0x00 }; |
| 206016 | + memset(pParse, 0, sizeof(pParse[0])); |
| 206017 | + switch( eType ){ |
| 206018 | + default: { |
| 206019 | + pParse->aBlob = aNull; |
| 206020 | + pParse->nBlob = 1; |
| 206021 | + return 0; |
| 206022 | + } |
| 206023 | + case SQLITE_BLOB: { |
| 206024 | + if( jsonFuncArgMightBeBinary(pArg) ){ |
| 206025 | + pParse->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 206026 | + pParse->nBlob = sqlite3_value_bytes(pArg); |
| 206027 | + }else{ |
| 206028 | + sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); |
| 206029 | + return 1; |
| 206030 | + } |
| 206031 | + break; |
| 206032 | + } |
| 206033 | + case SQLITE_TEXT: { |
| 206034 | + const char *zJson = (const char*)sqlite3_value_text(pArg); |
| 206035 | + int nJson = sqlite3_value_bytes(pArg); |
| 206036 | + if( zJson==0 ) return 1; |
| 206037 | + if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){ |
| 206038 | + pParse->zJson = (char*)zJson; |
| 206039 | + pParse->nJson = nJson; |
| 206040 | + if( jsonConvertTextToBlob(pParse, ctx) ){ |
| 206041 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206042 | + sqlite3_free(pParse->aBlob); |
| 206043 | + memset(pParse, 0, sizeof(pParse[0])); |
| 206044 | + return 1; |
| 206045 | + } |
| 206046 | + }else{ |
| 206047 | + jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson); |
| 206048 | + } |
| 206049 | + break; |
| 206050 | + } |
| 206051 | + case SQLITE_FLOAT: |
| 206052 | + case SQLITE_INTEGER: { |
| 206053 | + int n = sqlite3_value_bytes(pArg); |
| 206054 | + const char *z = (const char*)sqlite3_value_text(pArg); |
| 206055 | + int e = eType==SQLITE_INTEGER ? JSONB_INT : JSONB_FLOAT; |
| 206056 | + if( z==0 ) return 1; |
| 206057 | + jsonBlobAppendNode(pParse, e, n, z); |
| 206058 | + break; |
| 206059 | + } |
| 206060 | + } |
| 206061 | + if( pParse->oom ){ |
| 206062 | + sqlite3_result_error_nomem(ctx); |
| 206063 | + return 1; |
| 206064 | + }else{ |
| 206065 | + return 0; |
| 206066 | + } |
| 206067 | +} |
| 206068 | + |
| 206069 | +/* |
| 206070 | +** Generate a bad path error. |
| 206071 | +** |
| 206072 | +** If ctx is not NULL then push the error message into ctx and return NULL. |
| 206073 | +** If ctx is NULL, then return the text of the error message. |
| 206074 | +*/ |
| 206075 | +static char *jsonBadPathError( |
| 206076 | + sqlite3_context *ctx, /* The function call containing the error */ |
| 206077 | + const char *zPath /* The path with the problem */ |
| 206078 | +){ |
| 206079 | + char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); |
| 206080 | + if( ctx==0 ) return zMsg; |
| 206081 | + if( zMsg ){ |
| 206082 | + sqlite3_result_error(ctx, zMsg, -1); |
| 206083 | + sqlite3_free(zMsg); |
| 206084 | + }else{ |
| 206085 | + sqlite3_result_error_nomem(ctx); |
| 206086 | + } |
| 206087 | + return 0; |
| 206088 | +} |
| 206089 | + |
| 206090 | +/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent |
| 206091 | +** arguments come in parse where each pair contains a JSON path and |
| 206092 | +** content to insert or set at that patch. Do the updates |
| 206093 | +** and return the result. |
| 206094 | +** |
| 206095 | +** The specific operation is determined by eEdit, which can be one |
| 206096 | +** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET. |
| 206097 | +*/ |
| 206098 | +static void jsonInsertIntoBlob( |
| 206099 | + sqlite3_context *ctx, |
| 206100 | + int argc, |
| 206101 | + sqlite3_value **argv, |
| 206102 | + int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */ |
| 206103 | +){ |
| 206104 | + int i; |
| 206105 | + u32 rc = 0; |
| 206106 | + const char *zPath = 0; |
| 206107 | + int flgs; |
| 206108 | + JsonParse *p; |
| 206109 | + JsonParse ax; |
| 206110 | + |
| 206111 | + assert( (argc&1)==1 ); |
| 206112 | + flgs = argc==1 ? 0 : JSON_EDITABLE; |
| 206113 | + p = jsonParseFuncArg(ctx, argv[0], flgs); |
| 206114 | + if( p==0 ) return; |
| 206115 | + for(i=1; i<argc-1; i+=2){ |
| 206116 | + if( sqlite3_value_type(argv[i])==SQLITE_NULL ) continue; |
| 206117 | + zPath = (const char*)sqlite3_value_text(argv[i]); |
| 206118 | + if( zPath==0 ){ |
| 206119 | + sqlite3_result_error_nomem(ctx); |
| 206120 | + jsonParseFree(p); |
| 206121 | + return; |
| 206122 | + } |
| 206123 | + if( zPath[0]!='$' ) goto jsonInsertIntoBlob_patherror; |
| 206124 | + if( jsonFunctionArgToBlob(ctx, argv[i+1], &ax) ){ |
| 206125 | + jsonParseReset(&ax); |
| 206126 | + jsonParseFree(p); |
| 206127 | + return; |
| 206128 | + } |
| 206129 | + if( zPath[1]==0 ){ |
| 206130 | + if( eEdit==JEDIT_REPL || eEdit==JEDIT_SET ){ |
| 206131 | + jsonBlobEdit(p, 0, p->nBlob, ax.aBlob, ax.nBlob); |
| 206132 | + } |
| 206133 | + rc = 0; |
| 206134 | + }else{ |
| 206135 | + p->eEdit = eEdit; |
| 206136 | + p->nIns = ax.nBlob; |
| 206137 | + p->aIns = ax.aBlob; |
| 206138 | + p->delta = 0; |
| 206139 | + rc = jsonLookupStep(p, 0, zPath+1, 0); |
| 206140 | + } |
| 206141 | + jsonParseReset(&ax); |
| 206142 | + if( rc==JSON_LOOKUP_NOTFOUND ) continue; |
| 206143 | + if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror; |
| 206144 | + } |
| 206145 | + jsonReturnParse(ctx, p); |
| 206146 | + jsonParseFree(p); |
| 206147 | + return; |
| 206148 | + |
| 206149 | +jsonInsertIntoBlob_patherror: |
| 206150 | + jsonParseFree(p); |
| 206151 | + if( rc==JSON_LOOKUP_ERROR ){ |
| 206152 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206153 | + }else{ |
| 206154 | + jsonBadPathError(ctx, zPath); |
| 206155 | + } |
| 206156 | + return; |
| 206157 | +} |
| 206158 | + |
| 206159 | +/* |
| 206160 | +** Make a copy of a JsonParse object. The copy will be editable. |
| 206161 | +*/ |
| 206162 | + |
| 206163 | + |
| 206164 | +/* |
| 206165 | +** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob, |
| 206166 | +** from the SQL function argument pArg. Return a pointer to the new |
| 206167 | +** JsonParse object. |
| 206168 | +** |
| 206169 | +** Ownership of the new JsonParse object is passed to the caller. The |
| 206170 | +** caller should invoke jsonParseFree() on the return value when it |
| 206171 | +** has finished using it. |
| 206172 | +** |
| 206173 | +** If any errors are detected, an appropriate error messages is set |
| 206174 | +** using sqlite3_result_error() or the equivalent and this routine |
| 206175 | +** returns NULL. This routine also returns NULL if the pArg argument |
| 206176 | +** is an SQL NULL value, but no error message is set in that case. This |
| 206177 | +** is so that SQL functions that are given NULL arguments will return |
| 206178 | +** a NULL value. |
| 206179 | +*/ |
| 206180 | +static JsonParse *jsonParseFuncArg( |
| 206181 | + sqlite3_context *ctx, |
| 206182 | + sqlite3_value *pArg, |
| 206183 | + u32 flgs |
| 206184 | +){ |
| 206185 | + int eType; /* Datatype of pArg */ |
| 206186 | + JsonParse *p = 0; /* Value to be returned */ |
| 206187 | + JsonParse *pFromCache = 0; /* Value taken from cache */ |
| 206188 | + |
| 206189 | + assert( ctx!=0 ); |
| 206190 | + eType = sqlite3_value_type(pArg); |
| 206191 | + if( eType==SQLITE_NULL ){ |
| 206192 | + return 0; |
| 206193 | + } |
| 206194 | + pFromCache = jsonCacheSearch(ctx, pArg); |
| 206195 | + if( pFromCache ){ |
| 206196 | + pFromCache->nJPRef++; |
| 206197 | + if( (flgs & JSON_EDITABLE)==0 ){ |
| 206198 | + return pFromCache; |
| 206199 | + } |
| 206200 | + } |
| 206201 | +rebuild_from_cache: |
| 206202 | + p = sqlite3_malloc64( sizeof(*p) ); |
| 206203 | + if( p==0 ) goto json_pfa_oom; |
| 206204 | + memset(p, 0, sizeof(*p)); |
| 206205 | + p->nJPRef = 1; |
| 206206 | + if( pFromCache!=0 ){ |
| 206207 | + u32 nBlob = pFromCache->nBlob; |
| 206208 | + p->aBlob = sqlite3_malloc64( nBlob ); |
| 206209 | + if( p->aBlob==0 ) goto json_pfa_oom; |
| 206210 | + memcpy(p->aBlob, pFromCache->aBlob, nBlob); |
| 206211 | + p->nBlobAlloc = p->nBlob = nBlob; |
| 206212 | + p->hasNonstd = pFromCache->hasNonstd; |
| 206213 | + jsonParseFree(pFromCache); |
| 206214 | + return p; |
| 206215 | + } |
| 206216 | + if( eType==SQLITE_BLOB ){ |
| 206217 | + u32 n, sz = 0; |
| 206218 | + p->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 206219 | + p->nBlob = (u32)sqlite3_value_bytes(pArg); |
| 206220 | + if( p->nBlob==0 ){ |
| 206221 | + goto json_pfa_malformed; |
| 206222 | + } |
| 206223 | + if( NEVER(p->aBlob==0) ){ |
| 206224 | + goto json_pfa_oom; |
| 206225 | + } |
| 206226 | + if( (p->aBlob[0] & 0x0f)>JSONB_OBJECT ){ |
| 206227 | + goto json_pfa_malformed; |
| 206228 | + } |
| 206229 | + n = jsonbPayloadSize(p, 0, &sz); |
| 206230 | + if( n==0 |
| 206231 | + || sz+n!=p->nBlob |
| 206232 | + || ((p->aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0) |
| 206233 | + ){ |
| 206234 | + goto json_pfa_malformed; |
| 206235 | + } |
| 206236 | + if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){ |
| 206237 | + goto json_pfa_oom; |
| 206238 | + } |
| 206239 | + return p; |
| 206240 | + } |
| 206241 | + p->zJson = (char*)sqlite3_value_text(pArg); |
| 206242 | + p->nJson = sqlite3_value_bytes(pArg); |
| 206243 | + if( p->nJson==0 ) goto json_pfa_malformed; |
| 206244 | + if( NEVER(p->zJson==0) ) goto json_pfa_oom; |
| 206245 | + if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){ |
| 206246 | + if( flgs & JSON_KEEPERROR ){ |
| 206247 | + p->nErr = 1; |
| 206248 | + return p; |
| 206249 | + }else{ |
| 206250 | + jsonParseFree(p); |
| 206251 | + return 0; |
| 206252 | + } |
| 206253 | + }else{ |
| 206254 | + int isRCStr = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref); |
| 206255 | + int rc; |
| 206256 | + if( !isRCStr ){ |
| 206257 | + char *zNew = sqlite3RCStrNew( p->nJson ); |
| 206258 | + if( zNew==0 ) goto json_pfa_oom; |
| 206259 | + memcpy(zNew, p->zJson, p->nJson); |
| 206260 | + p->zJson = zNew; |
| 206261 | + p->zJson[p->nJson] = 0; |
| 206262 | + }else{ |
| 206263 | + sqlite3RCStrRef(p->zJson); |
| 206264 | + } |
| 206265 | + p->bJsonIsRCStr = 1; |
| 206266 | + rc = jsonCacheInsert(ctx, p); |
| 206267 | + if( rc==SQLITE_NOMEM ) goto json_pfa_oom; |
| 206268 | + if( flgs & JSON_EDITABLE ){ |
| 206269 | + pFromCache = p; |
| 206270 | + p = 0; |
| 206271 | + goto rebuild_from_cache; |
| 206272 | + } |
| 206273 | + } |
| 206274 | + return p; |
| 206275 | + |
| 206276 | +json_pfa_malformed: |
| 206277 | + if( flgs & JSON_KEEPERROR ){ |
| 206278 | + p->nErr = 1; |
| 206279 | + return p; |
| 206280 | + }else{ |
| 206281 | + jsonParseFree(p); |
| 206282 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206283 | + return 0; |
| 206284 | + } |
| 206285 | + |
| 206286 | +json_pfa_oom: |
| 206287 | + jsonParseFree(pFromCache); |
| 206288 | + jsonParseFree(p); |
| 206289 | + sqlite3_result_error_nomem(ctx); |
| 206290 | + return 0; |
| 206291 | +} |
| 206292 | + |
| 206293 | +/* |
| 206294 | +** Make the return value of a JSON function either the raw JSONB blob |
| 206295 | +** or make it JSON text, depending on whether the JSON_BLOB flag is |
| 206296 | +** set on the function. |
| 206297 | +*/ |
| 206298 | +static void jsonReturnParse( |
| 206299 | + sqlite3_context *ctx, |
| 206300 | + JsonParse *p |
| 206301 | +){ |
| 206302 | + int flgs; |
| 206303 | + if( p->oom ){ |
| 206304 | + sqlite3_result_error_nomem(ctx); |
| 206305 | + return; |
| 206306 | + } |
| 206307 | + flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 206308 | + if( flgs & JSON_BLOB ){ |
| 206309 | + if( p->nBlobAlloc>0 && !p->bReadOnly ){ |
| 206310 | + sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC); |
| 206311 | + p->nBlobAlloc = 0; |
| 206312 | + }else{ |
| 206313 | + sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT); |
| 206314 | + } |
| 206315 | + }else{ |
| 206316 | + JsonString s; |
| 206317 | + jsonStringInit(&s, ctx); |
| 206318 | + jsonXlateBlobToText(p, 0, &s); |
| 206319 | + jsonReturnString(&s, p, ctx); |
| 206320 | + sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206321 | + } |
| 206322 | +} |
| 204950 | 206323 | |
| 204951 | 206324 | /**************************************************************************** |
| 204952 | 206325 | ** SQL functions used for testing and debugging |
| 204953 | 206326 | ****************************************************************************/ |
| 204954 | 206327 | |
| 204955 | 206328 | #if SQLITE_DEBUG |
| 204956 | 206329 | /* |
| 204957 | | -** Print N node entries. |
| 204958 | | -*/ |
| 204959 | | -static void jsonDebugPrintNodeEntries( |
| 204960 | | - JsonNode *aNode, /* First node entry to print */ |
| 204961 | | - int N /* Number of node entries to print */ |
| 204962 | | -){ |
| 204963 | | - int i; |
| 204964 | | - for(i=0; i<N; i++){ |
| 204965 | | - const char *zType; |
| 204966 | | - if( aNode[i].jnFlags & JNODE_LABEL ){ |
| 204967 | | - zType = "label"; |
| 204968 | | - }else{ |
| 204969 | | - zType = jsonType[aNode[i].eType]; |
| 204970 | | - } |
| 204971 | | - printf("node %4u: %-7s n=%-5d", i, zType, aNode[i].n); |
| 204972 | | - if( (aNode[i].jnFlags & ~JNODE_LABEL)!=0 ){ |
| 204973 | | - u8 f = aNode[i].jnFlags; |
| 204974 | | - if( f & JNODE_RAW ) printf(" RAW"); |
| 204975 | | - if( f & JNODE_ESCAPE ) printf(" ESCAPE"); |
| 204976 | | - if( f & JNODE_REMOVE ) printf(" REMOVE"); |
| 204977 | | - if( f & JNODE_REPLACE ) printf(" REPLACE"); |
| 204978 | | - if( f & JNODE_APPEND ) printf(" APPEND"); |
| 204979 | | - if( f & JNODE_JSON5 ) printf(" JSON5"); |
| 204980 | | - } |
| 204981 | | - switch( aNode[i].eU ){ |
| 204982 | | - case 1: printf(" zJContent=[%.*s]\n", |
| 204983 | | - aNode[i].n, aNode[i].u.zJContent); break; |
| 204984 | | - case 2: printf(" iAppend=%u\n", aNode[i].u.iAppend); break; |
| 204985 | | - case 3: printf(" iKey=%u\n", aNode[i].u.iKey); break; |
| 204986 | | - case 4: printf(" iPrev=%u\n", aNode[i].u.iPrev); break; |
| 204987 | | - default: printf("\n"); |
| 204988 | | - } |
| 204989 | | - } |
| 204990 | | -} |
| 204991 | | -#endif /* SQLITE_DEBUG */ |
| 204992 | | - |
| 204993 | | - |
| 204994 | | -#if 0 /* 1 for debugging. 0 normally. Requires -DSQLITE_DEBUG too */ |
| 204995 | | -static void jsonDebugPrintParse(JsonParse *p){ |
| 204996 | | - jsonDebugPrintNodeEntries(p->aNode, p->nNode); |
| 204997 | | -} |
| 204998 | | -static void jsonDebugPrintNode(JsonNode *pNode){ |
| 204999 | | - jsonDebugPrintNodeEntries(pNode, jsonNodeSize(pNode)); |
| 205000 | | -} |
| 205001 | | -#else |
| 205002 | | - /* The usual case */ |
| 205003 | | -# define jsonDebugPrintNode(X) |
| 205004 | | -# define jsonDebugPrintParse(X) |
| 205005 | | -#endif |
| 206330 | +** Decode JSONB bytes in aBlob[] starting at iStart through but not |
| 206331 | +** including iEnd. Indent the |
| 206332 | +** content by nIndent spaces. |
| 206333 | +*/ |
| 206334 | +static void jsonDebugPrintBlob( |
| 206335 | + JsonParse *pParse, /* JSON content */ |
| 206336 | + u32 iStart, /* Start rendering here */ |
| 206337 | + u32 iEnd, /* Do not render this byte or any byte after this one */ |
| 206338 | + int nIndent /* Indent by this many spaces */ |
| 206339 | +){ |
| 206340 | + while( iStart<iEnd ){ |
| 206341 | + u32 i, n, nn, sz = 0; |
| 206342 | + int showContent = 1; |
| 206343 | + u8 x = pParse->aBlob[iStart] & 0x0f; |
| 206344 | + u32 savedNBlob = pParse->nBlob; |
| 206345 | + printf("%5d:%*s", iStart, nIndent, ""); |
| 206346 | + if( pParse->nBlobAlloc>pParse->nBlob ){ |
| 206347 | + pParse->nBlob = pParse->nBlobAlloc; |
| 206348 | + } |
| 206349 | + nn = n = jsonbPayloadSize(pParse, iStart, &sz); |
| 206350 | + if( nn==0 ) nn = 1; |
| 206351 | + if( sz>0 && x<JSONB_ARRAY ){ |
| 206352 | + nn += sz; |
| 206353 | + } |
| 206354 | + for(i=0; i<nn; i++) printf(" %02x", pParse->aBlob[iStart+i]); |
| 206355 | + if( n==0 ){ |
| 206356 | + printf(" ERROR invalid node size\n"); |
| 206357 | + iStart = n==0 ? iStart+1 : iEnd; |
| 206358 | + continue; |
| 206359 | + } |
| 206360 | + pParse->nBlob = savedNBlob; |
| 206361 | + if( iStart+n+sz>iEnd ){ |
| 206362 | + iEnd = iStart+n+sz; |
| 206363 | + if( iEnd>pParse->nBlob ){ |
| 206364 | + if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){ |
| 206365 | + iEnd = pParse->nBlobAlloc; |
| 206366 | + }else{ |
| 206367 | + iEnd = pParse->nBlob; |
| 206368 | + } |
| 206369 | + } |
| 206370 | + } |
| 206371 | + printf(" <-- "); |
| 206372 | + switch( x ){ |
| 206373 | + case JSONB_NULL: printf("null"); break; |
| 206374 | + case JSONB_TRUE: printf("true"); break; |
| 206375 | + case JSONB_FALSE: printf("false"); break; |
| 206376 | + case JSONB_INT: printf("int"); break; |
| 206377 | + case JSONB_INT5: printf("int5"); break; |
| 206378 | + case JSONB_FLOAT: printf("float"); break; |
| 206379 | + case JSONB_FLOAT5: printf("float5"); break; |
| 206380 | + case JSONB_TEXT: printf("text"); break; |
| 206381 | + case JSONB_TEXTJ: printf("textj"); break; |
| 206382 | + case JSONB_TEXT5: printf("text5"); break; |
| 206383 | + case JSONB_TEXTRAW: printf("textraw"); break; |
| 206384 | + case JSONB_ARRAY: { |
| 206385 | + printf("array, %u bytes\n", sz); |
| 206386 | + jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2); |
| 206387 | + showContent = 0; |
| 206388 | + break; |
| 206389 | + } |
| 206390 | + case JSONB_OBJECT: { |
| 206391 | + printf("object, %u bytes\n", sz); |
| 206392 | + jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2); |
| 206393 | + showContent = 0; |
| 206394 | + break; |
| 206395 | + } |
| 206396 | + default: { |
| 206397 | + printf("ERROR: unknown node type\n"); |
| 206398 | + showContent = 0; |
| 206399 | + break; |
| 206400 | + } |
| 206401 | + } |
| 206402 | + if( showContent ){ |
| 206403 | + if( sz==0 && x<=JSONB_FALSE ){ |
| 206404 | + printf("\n"); |
| 206405 | + }else{ |
| 206406 | + u32 i; |
| 206407 | + printf(": \""); |
| 206408 | + for(i=iStart+n; i<iStart+n+sz; i++){ |
| 206409 | + u8 c = pParse->aBlob[i]; |
| 206410 | + if( c<0x20 || c>=0x7f ) c = '.'; |
| 206411 | + putchar(c); |
| 206412 | + } |
| 206413 | + printf("\"\n"); |
| 206414 | + } |
| 206415 | + } |
| 206416 | + iStart += n + sz; |
| 206417 | + } |
| 206418 | +} |
| 206419 | +static void jsonShowParse(JsonParse *pParse){ |
| 206420 | + if( pParse==0 ){ |
| 206421 | + printf("NULL pointer\n"); |
| 206422 | + return; |
| 206423 | + }else{ |
| 206424 | + printf("nBlobAlloc = %u\n", pParse->nBlobAlloc); |
| 206425 | + printf("nBlob = %u\n", pParse->nBlob); |
| 206426 | + printf("delta = %d\n", pParse->delta); |
| 206427 | + if( pParse->nBlob==0 ) return; |
| 206428 | + printf("content (bytes 0..%u):\n", pParse->nBlob-1); |
| 206429 | + } |
| 206430 | + jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0); |
| 206431 | +} |
| 206432 | +#endif /* SQLITE_DEBUG */ |
| 205006 | 206433 | |
| 205007 | 206434 | #ifdef SQLITE_DEBUG |
| 205008 | 206435 | /* |
| 205009 | 206436 | ** SQL function: json_parse(JSON) |
| 205010 | 206437 | ** |
| 205011 | | -** Parse JSON using jsonParseCached(). Then print a dump of that |
| 205012 | | -** parse on standard output. Return the mimified JSON result, just |
| 205013 | | -** like the json() function. |
| 206438 | +** Parse JSON using jsonParseFuncArg(). Then print a dump of that |
| 206439 | +** parse on standard output. |
| 205014 | 206440 | */ |
| 205015 | 206441 | static void jsonParseFunc( |
| 205016 | 206442 | sqlite3_context *ctx, |
| 205017 | 206443 | int argc, |
| 205018 | 206444 | sqlite3_value **argv |
| 205019 | 206445 | ){ |
| 205020 | 206446 | JsonParse *p; /* The parse */ |
| 205021 | 206447 | |
| 205022 | 206448 | assert( argc==1 ); |
| 205023 | | - p = jsonParseCached(ctx, argv[0], ctx, 0); |
| 205024 | | - if( p==0 ) return; |
| 205025 | | - printf("nNode = %u\n", p->nNode); |
| 205026 | | - printf("nAlloc = %u\n", p->nAlloc); |
| 205027 | | - printf("nJson = %d\n", p->nJson); |
| 205028 | | - printf("nAlt = %d\n", p->nAlt); |
| 205029 | | - printf("nErr = %u\n", p->nErr); |
| 205030 | | - printf("oom = %u\n", p->oom); |
| 205031 | | - printf("hasNonstd = %u\n", p->hasNonstd); |
| 205032 | | - printf("useMod = %u\n", p->useMod); |
| 205033 | | - printf("hasMod = %u\n", p->hasMod); |
| 205034 | | - printf("nJPRef = %u\n", p->nJPRef); |
| 205035 | | - printf("iSubst = %u\n", p->iSubst); |
| 205036 | | - printf("iHold = %u\n", p->iHold); |
| 205037 | | - jsonDebugPrintNodeEntries(p->aNode, p->nNode); |
| 205038 | | - jsonReturnJson(p, p->aNode, ctx, 1, 0); |
| 205039 | | -} |
| 205040 | | - |
| 205041 | | -/* |
| 205042 | | -** The json_test1(JSON) function return true (1) if the input is JSON |
| 205043 | | -** text generated by another json function. It returns (0) if the input |
| 205044 | | -** is not known to be JSON. |
| 205045 | | -*/ |
| 205046 | | -static void jsonTest1Func( |
| 205047 | | - sqlite3_context *ctx, |
| 205048 | | - int argc, |
| 205049 | | - sqlite3_value **argv |
| 205050 | | -){ |
| 205051 | | - UNUSED_PARAMETER(argc); |
| 205052 | | - sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); |
| 206449 | + p = jsonParseFuncArg(ctx, argv[0], 0); |
| 206450 | + jsonShowParse(p); |
| 206451 | + jsonParseFree(p); |
| 205053 | 206452 | } |
| 205054 | 206453 | #endif /* SQLITE_DEBUG */ |
| 205055 | 206454 | |
| 205056 | 206455 | /**************************************************************************** |
| 205057 | 206456 | ** Scalar SQL function implementations |
| 205058 | 206457 | ****************************************************************************/ |
| 205059 | 206458 | |
| 205060 | 206459 | /* |
| 205061 | | -** Implementation of the json_QUOTE(VALUE) function. Return a JSON value |
| 206460 | +** Implementation of the json_quote(VALUE) function. Return a JSON value |
| 205062 | 206461 | ** corresponding to the SQL value input. Mostly this means putting |
| 205063 | 206462 | ** double-quotes around strings and returning the unquoted string "null" |
| 205064 | 206463 | ** when given a NULL input. |
| 205065 | 206464 | */ |
| 205066 | 206465 | static void jsonQuoteFunc( |
| | @@ -205069,13 +206468,13 @@ |
| 205069 | 206468 | sqlite3_value **argv |
| 205070 | 206469 | ){ |
| 205071 | 206470 | JsonString jx; |
| 205072 | 206471 | UNUSED_PARAMETER(argc); |
| 205073 | 206472 | |
| 205074 | | - jsonInit(&jx, ctx); |
| 205075 | | - jsonAppendValue(&jx, argv[0]); |
| 205076 | | - jsonResult(&jx); |
| 206473 | + jsonStringInit(&jx, ctx); |
| 206474 | + jsonAppendSqlValue(&jx, argv[0]); |
| 206475 | + jsonReturnString(&jx, 0, 0); |
| 205077 | 206476 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 205078 | 206477 | } |
| 205079 | 206478 | |
| 205080 | 206479 | /* |
| 205081 | 206480 | ** Implementation of the json_array(VALUE,...) function. Return a JSON |
| | @@ -205088,21 +206487,20 @@ |
| 205088 | 206487 | sqlite3_value **argv |
| 205089 | 206488 | ){ |
| 205090 | 206489 | int i; |
| 205091 | 206490 | JsonString jx; |
| 205092 | 206491 | |
| 205093 | | - jsonInit(&jx, ctx); |
| 206492 | + jsonStringInit(&jx, ctx); |
| 205094 | 206493 | jsonAppendChar(&jx, '['); |
| 205095 | 206494 | for(i=0; i<argc; i++){ |
| 205096 | 206495 | jsonAppendSeparator(&jx); |
| 205097 | | - jsonAppendValue(&jx, argv[i]); |
| 206496 | + jsonAppendSqlValue(&jx, argv[i]); |
| 205098 | 206497 | } |
| 205099 | 206498 | jsonAppendChar(&jx, ']'); |
| 205100 | | - jsonResult(&jx); |
| 206499 | + jsonReturnString(&jx, 0, 0); |
| 205101 | 206500 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 205102 | 206501 | } |
| 205103 | | - |
| 205104 | 206502 | |
| 205105 | 206503 | /* |
| 205106 | 206504 | ** json_array_length(JSON) |
| 205107 | 206505 | ** json_array_length(JSON, PATH) |
| 205108 | 206506 | ** |
| | @@ -205113,50 +206511,57 @@ |
| 205113 | 206511 | sqlite3_context *ctx, |
| 205114 | 206512 | int argc, |
| 205115 | 206513 | sqlite3_value **argv |
| 205116 | 206514 | ){ |
| 205117 | 206515 | JsonParse *p; /* The parse */ |
| 205118 | | - sqlite3_int64 n = 0; |
| 206516 | + sqlite3_int64 cnt = 0; |
| 205119 | 206517 | u32 i; |
| 205120 | | - JsonNode *pNode; |
| 206518 | + u8 eErr = 0; |
| 205121 | 206519 | |
| 205122 | | - p = jsonParseCached(ctx, argv[0], ctx, 0); |
| 206520 | + p = jsonParseFuncArg(ctx, argv[0], 0); |
| 205123 | 206521 | if( p==0 ) return; |
| 205124 | | - assert( p->nNode ); |
| 205125 | 206522 | if( argc==2 ){ |
| 205126 | 206523 | const char *zPath = (const char*)sqlite3_value_text(argv[1]); |
| 205127 | | - pNode = jsonLookup(p, zPath, 0, ctx); |
| 205128 | | - }else{ |
| 205129 | | - pNode = p->aNode; |
| 205130 | | - } |
| 205131 | | - if( pNode==0 ){ |
| 205132 | | - return; |
| 205133 | | - } |
| 205134 | | - if( pNode->eType==JSON_ARRAY ){ |
| 205135 | | - while( 1 /*exit-by-break*/ ){ |
| 205136 | | - i = 1; |
| 205137 | | - while( i<=pNode->n ){ |
| 205138 | | - if( (pNode[i].jnFlags & JNODE_REMOVE)==0 ) n++; |
| 205139 | | - i += jsonNodeSize(&pNode[i]); |
| 205140 | | - } |
| 205141 | | - if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; |
| 205142 | | - if( p->useMod==0 ) break; |
| 205143 | | - assert( pNode->eU==2 ); |
| 205144 | | - pNode = &p->aNode[pNode->u.iAppend]; |
| 205145 | | - } |
| 205146 | | - } |
| 205147 | | - sqlite3_result_int64(ctx, n); |
| 205148 | | -} |
| 205149 | | - |
| 205150 | | -/* |
| 205151 | | -** Bit values for the flags passed into jsonExtractFunc() or |
| 205152 | | -** jsonSetFunc() via the user-data value. |
| 205153 | | -*/ |
| 205154 | | -#define JSON_JSON 0x01 /* Result is always JSON */ |
| 205155 | | -#define JSON_SQL 0x02 /* Result is always SQL */ |
| 205156 | | -#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ |
| 205157 | | -#define JSON_ISSET 0x04 /* json_set(), not json_insert() */ |
| 206524 | + if( zPath==0 ){ |
| 206525 | + jsonParseFree(p); |
| 206526 | + return; |
| 206527 | + } |
| 206528 | + i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0); |
| 206529 | + if( JSON_LOOKUP_ISERROR(i) ){ |
| 206530 | + if( i==JSON_LOOKUP_NOTFOUND ){ |
| 206531 | + /* no-op */ |
| 206532 | + }else if( i==JSON_LOOKUP_PATHERROR ){ |
| 206533 | + jsonBadPathError(ctx, zPath); |
| 206534 | + }else{ |
| 206535 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206536 | + } |
| 206537 | + eErr = 1; |
| 206538 | + i = 0; |
| 206539 | + } |
| 206540 | + }else{ |
| 206541 | + i = 0; |
| 206542 | + } |
| 206543 | + if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){ |
| 206544 | + cnt = jsonbArrayCount(p, i); |
| 206545 | + } |
| 206546 | + if( !eErr ) sqlite3_result_int64(ctx, cnt); |
| 206547 | + jsonParseFree(p); |
| 206548 | +} |
| 206549 | + |
| 206550 | +/* True if the string is all digits */ |
| 206551 | +static int jsonAllDigits(const char *z, int n){ |
| 206552 | + int i; |
| 206553 | + for(i=0; i<n && sqlite3Isdigit(z[i]); i++){} |
| 206554 | + return i==n; |
| 206555 | +} |
| 206556 | + |
| 206557 | +/* True if the string is all alphanumerics and underscores */ |
| 206558 | +static int jsonAllAlphanum(const char *z, int n){ |
| 206559 | + int i; |
| 206560 | + for(i=0; i<n && (sqlite3Isalnum(z[i]) || z[i]=='_'); i++){} |
| 206561 | + return i==n; |
| 206562 | +} |
| 205158 | 206563 | |
| 205159 | 206564 | /* |
| 205160 | 206565 | ** json_extract(JSON, PATH, ...) |
| 205161 | 206566 | ** "->"(JSON,PATH) |
| 205162 | 206567 | ** "->>"(JSON,PATH) |
| | @@ -205179,154 +206584,310 @@ |
| 205179 | 206584 | static void jsonExtractFunc( |
| 205180 | 206585 | sqlite3_context *ctx, |
| 205181 | 206586 | int argc, |
| 205182 | 206587 | sqlite3_value **argv |
| 205183 | 206588 | ){ |
| 205184 | | - JsonParse *p; /* The parse */ |
| 205185 | | - JsonNode *pNode; |
| 205186 | | - const char *zPath; |
| 205187 | | - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 205188 | | - JsonString jx; |
| 206589 | + JsonParse *p = 0; /* The parse */ |
| 206590 | + int flags; /* Flags associated with the function */ |
| 206591 | + int i; /* Loop counter */ |
| 206592 | + JsonString jx; /* String for array result */ |
| 205189 | 206593 | |
| 205190 | 206594 | if( argc<2 ) return; |
| 205191 | | - p = jsonParseCached(ctx, argv[0], ctx, 0); |
| 206595 | + p = jsonParseFuncArg(ctx, argv[0], 0); |
| 205192 | 206596 | if( p==0 ) return; |
| 205193 | | - if( argc==2 ){ |
| 206597 | + flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 206598 | + jsonStringInit(&jx, ctx); |
| 206599 | + if( argc>2 ){ |
| 206600 | + jsonAppendChar(&jx, '['); |
| 206601 | + } |
| 206602 | + for(i=1; i<argc; i++){ |
| 205194 | 206603 | /* With a single PATH argument */ |
| 205195 | | - zPath = (const char*)sqlite3_value_text(argv[1]); |
| 205196 | | - if( zPath==0 ) return; |
| 205197 | | - if( flags & JSON_ABPATH ){ |
| 205198 | | - if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){ |
| 205199 | | - /* The -> and ->> operators accept abbreviated PATH arguments. This |
| 205200 | | - ** is mostly for compatibility with PostgreSQL, but also for |
| 205201 | | - ** convenience. |
| 205202 | | - ** |
| 205203 | | - ** NUMBER ==> $[NUMBER] // PG compatible |
| 205204 | | - ** LABEL ==> $.LABEL // PG compatible |
| 205205 | | - ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience |
| 205206 | | - */ |
| 205207 | | - jsonInit(&jx, ctx); |
| 205208 | | - if( sqlite3Isdigit(zPath[0]) ){ |
| 205209 | | - jsonAppendRawNZ(&jx, "$[", 2); |
| 205210 | | - jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); |
| 205211 | | - jsonAppendRawNZ(&jx, "]", 2); |
| 205212 | | - }else{ |
| 205213 | | - jsonAppendRawNZ(&jx, "$.", 1 + (zPath[0]!='[')); |
| 205214 | | - jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); |
| 205215 | | - jsonAppendChar(&jx, 0); |
| 205216 | | - } |
| 205217 | | - pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx); |
| 205218 | | - jsonReset(&jx); |
| 205219 | | - }else{ |
| 205220 | | - pNode = jsonLookup(p, zPath, 0, ctx); |
| 205221 | | - } |
| 205222 | | - if( pNode ){ |
| 206604 | + const char *zPath = (const char*)sqlite3_value_text(argv[i]); |
| 206605 | + int nPath; |
| 206606 | + u32 j; |
| 206607 | + if( zPath==0 ) goto json_extract_error; |
| 206608 | + nPath = sqlite3Strlen30(zPath); |
| 206609 | + if( zPath[0]=='$' ){ |
| 206610 | + j = jsonLookupStep(p, 0, zPath+1, 0); |
| 206611 | + }else if( (flags & JSON_ABPATH) ){ |
| 206612 | + /* The -> and ->> operators accept abbreviated PATH arguments. This |
| 206613 | + ** is mostly for compatibility with PostgreSQL, but also for |
| 206614 | + ** convenience. |
| 206615 | + ** |
| 206616 | + ** NUMBER ==> $[NUMBER] // PG compatible |
| 206617 | + ** LABEL ==> $.LABEL // PG compatible |
| 206618 | + ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience |
| 206619 | + */ |
| 206620 | + jsonStringInit(&jx, ctx); |
| 206621 | + if( jsonAllDigits(zPath, nPath) ){ |
| 206622 | + jsonAppendRawNZ(&jx, "[", 1); |
| 206623 | + jsonAppendRaw(&jx, zPath, nPath); |
| 206624 | + jsonAppendRawNZ(&jx, "]", 2); |
| 206625 | + }else if( jsonAllAlphanum(zPath, nPath) ){ |
| 206626 | + jsonAppendRawNZ(&jx, ".", 1); |
| 206627 | + jsonAppendRaw(&jx, zPath, nPath); |
| 206628 | + }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){ |
| 206629 | + jsonAppendRaw(&jx, zPath, nPath); |
| 206630 | + }else{ |
| 206631 | + jsonAppendRawNZ(&jx, ".\"", 2); |
| 206632 | + jsonAppendRaw(&jx, zPath, nPath); |
| 206633 | + jsonAppendRawNZ(&jx, "\"", 1); |
| 206634 | + } |
| 206635 | + jsonStringTerminate(&jx); |
| 206636 | + j = jsonLookupStep(p, 0, jx.zBuf, 0); |
| 206637 | + jsonStringReset(&jx); |
| 206638 | + }else{ |
| 206639 | + jsonBadPathError(ctx, zPath); |
| 206640 | + goto json_extract_error; |
| 206641 | + } |
| 206642 | + if( j<p->nBlob ){ |
| 206643 | + if( argc==2 ){ |
| 205223 | 206644 | if( flags & JSON_JSON ){ |
| 205224 | | - jsonReturnJson(p, pNode, ctx, 0, 0); |
| 205225 | | - }else{ |
| 205226 | | - jsonReturn(p, pNode, ctx, 1); |
| 205227 | | - } |
| 205228 | | - } |
| 205229 | | - }else{ |
| 205230 | | - pNode = jsonLookup(p, zPath, 0, ctx); |
| 205231 | | - if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx, 0); |
| 205232 | | - } |
| 205233 | | - }else{ |
| 205234 | | - /* Two or more PATH arguments results in a JSON array with each |
| 205235 | | - ** element of the array being the value selected by one of the PATHs */ |
| 205236 | | - int i; |
| 205237 | | - jsonInit(&jx, ctx); |
| 205238 | | - jsonAppendChar(&jx, '['); |
| 205239 | | - for(i=1; i<argc; i++){ |
| 205240 | | - zPath = (const char*)sqlite3_value_text(argv[i]); |
| 205241 | | - pNode = jsonLookup(p, zPath, 0, ctx); |
| 205242 | | - if( p->nErr ) break; |
| 205243 | | - jsonAppendSeparator(&jx); |
| 205244 | | - if( pNode ){ |
| 205245 | | - jsonRenderNode(p, pNode, &jx); |
| 205246 | | - }else{ |
| 206645 | + jsonStringInit(&jx, ctx); |
| 206646 | + jsonXlateBlobToText(p, j, &jx); |
| 206647 | + jsonReturnString(&jx, 0, 0); |
| 206648 | + jsonStringReset(&jx); |
| 206649 | + assert( (flags & JSON_BLOB)==0 ); |
| 206650 | + sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206651 | + }else{ |
| 206652 | + jsonReturnFromBlob(p, j, ctx, 0); |
| 206653 | + if( (flags & (JSON_SQL|JSON_BLOB))==0 |
| 206654 | + && (p->aBlob[j]&0x0f)>=JSONB_ARRAY |
| 206655 | + ){ |
| 206656 | + sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 206657 | + } |
| 206658 | + } |
| 206659 | + }else{ |
| 206660 | + jsonAppendSeparator(&jx); |
| 206661 | + jsonXlateBlobToText(p, j, &jx); |
| 206662 | + } |
| 206663 | + }else if( j==JSON_LOOKUP_NOTFOUND ){ |
| 206664 | + if( argc==2 ){ |
| 206665 | + goto json_extract_error; /* Return NULL if not found */ |
| 206666 | + }else{ |
| 206667 | + jsonAppendSeparator(&jx); |
| 205247 | 206668 | jsonAppendRawNZ(&jx, "null", 4); |
| 205248 | 206669 | } |
| 206670 | + }else if( j==JSON_LOOKUP_ERROR ){ |
| 206671 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206672 | + goto json_extract_error; |
| 206673 | + }else{ |
| 206674 | + jsonBadPathError(ctx, zPath); |
| 206675 | + goto json_extract_error; |
| 205249 | 206676 | } |
| 205250 | | - if( i==argc ){ |
| 205251 | | - jsonAppendChar(&jx, ']'); |
| 205252 | | - jsonResult(&jx); |
| 206677 | + } |
| 206678 | + if( argc>2 ){ |
| 206679 | + jsonAppendChar(&jx, ']'); |
| 206680 | + jsonReturnString(&jx, 0, 0); |
| 206681 | + if( (flags & JSON_BLOB)==0 ){ |
| 205253 | 206682 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 205254 | 206683 | } |
| 205255 | | - jsonReset(&jx); |
| 205256 | | - } |
| 205257 | | -} |
| 205258 | | - |
| 205259 | | -/* This is the RFC 7396 MergePatch algorithm. |
| 205260 | | -*/ |
| 205261 | | -static JsonNode *jsonMergePatch( |
| 205262 | | - JsonParse *pParse, /* The JSON parser that contains the TARGET */ |
| 205263 | | - u32 iTarget, /* Node of the TARGET in pParse */ |
| 205264 | | - JsonNode *pPatch /* The PATCH */ |
| 205265 | | -){ |
| 205266 | | - u32 i, j; |
| 205267 | | - u32 iRoot; |
| 205268 | | - JsonNode *pTarget; |
| 205269 | | - if( pPatch->eType!=JSON_OBJECT ){ |
| 205270 | | - return pPatch; |
| 205271 | | - } |
| 205272 | | - assert( iTarget<pParse->nNode ); |
| 205273 | | - pTarget = &pParse->aNode[iTarget]; |
| 205274 | | - assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); |
| 205275 | | - if( pTarget->eType!=JSON_OBJECT ){ |
| 205276 | | - jsonRemoveAllNulls(pPatch); |
| 205277 | | - return pPatch; |
| 205278 | | - } |
| 205279 | | - iRoot = iTarget; |
| 205280 | | - for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){ |
| 205281 | | - u32 nKey; |
| 205282 | | - const char *zKey; |
| 205283 | | - assert( pPatch[i].eType==JSON_STRING ); |
| 205284 | | - assert( pPatch[i].jnFlags & JNODE_LABEL ); |
| 205285 | | - assert( pPatch[i].eU==1 ); |
| 205286 | | - nKey = pPatch[i].n; |
| 205287 | | - zKey = pPatch[i].u.zJContent; |
| 205288 | | - for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){ |
| 205289 | | - assert( pTarget[j].eType==JSON_STRING ); |
| 205290 | | - assert( pTarget[j].jnFlags & JNODE_LABEL ); |
| 205291 | | - if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){ |
| 205292 | | - if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ) break; |
| 205293 | | - if( pPatch[i+1].eType==JSON_NULL ){ |
| 205294 | | - pTarget[j+1].jnFlags |= JNODE_REMOVE; |
| 205295 | | - }else{ |
| 205296 | | - JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]); |
| 205297 | | - if( pNew==0 ) return 0; |
| 205298 | | - if( pNew!=&pParse->aNode[iTarget+j+1] ){ |
| 205299 | | - jsonParseAddSubstNode(pParse, iTarget+j+1); |
| 205300 | | - jsonParseAddNodeArray(pParse, pNew, jsonNodeSize(pNew)); |
| 205301 | | - } |
| 205302 | | - pTarget = &pParse->aNode[iTarget]; |
| 205303 | | - } |
| 205304 | | - break; |
| 205305 | | - } |
| 205306 | | - } |
| 205307 | | - if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){ |
| 205308 | | - int iStart; |
| 205309 | | - JsonNode *pApnd; |
| 205310 | | - u32 nApnd; |
| 205311 | | - iStart = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); |
| 205312 | | - jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); |
| 205313 | | - pApnd = &pPatch[i+1]; |
| 205314 | | - if( pApnd->eType==JSON_OBJECT ) jsonRemoveAllNulls(pApnd); |
| 205315 | | - nApnd = jsonNodeSize(pApnd); |
| 205316 | | - jsonParseAddNodeArray(pParse, pApnd, jsonNodeSize(pApnd)); |
| 205317 | | - if( pParse->oom ) return 0; |
| 205318 | | - pParse->aNode[iStart].n = 1+nApnd; |
| 205319 | | - pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; |
| 205320 | | - pParse->aNode[iRoot].u.iAppend = iStart; |
| 205321 | | - VVA( pParse->aNode[iRoot].eU = 2 ); |
| 205322 | | - iRoot = iStart; |
| 205323 | | - pTarget = &pParse->aNode[iTarget]; |
| 205324 | | - } |
| 205325 | | - } |
| 205326 | | - return pTarget; |
| 205327 | | -} |
| 206684 | + } |
| 206685 | +json_extract_error: |
| 206686 | + jsonStringReset(&jx); |
| 206687 | + jsonParseFree(p); |
| 206688 | + return; |
| 206689 | +} |
| 206690 | + |
| 206691 | +/* |
| 206692 | +** Return codes for jsonMergePatch() |
| 206693 | +*/ |
| 206694 | +#define JSON_MERGE_OK 0 /* Success */ |
| 206695 | +#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */ |
| 206696 | +#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */ |
| 206697 | +#define JSON_MERGE_OOM 3 /* Out-of-memory condition */ |
| 206698 | + |
| 206699 | +/* |
| 206700 | +** RFC-7396 MergePatch for two JSONB blobs. |
| 206701 | +** |
| 206702 | +** pTarget is the target. pPatch is the patch. The target is updated |
| 206703 | +** in place. The patch is read-only. |
| 206704 | +** |
| 206705 | +** The original RFC-7396 algorithm is this: |
| 206706 | +** |
| 206707 | +** define MergePatch(Target, Patch): |
| 206708 | +** if Patch is an Object: |
| 206709 | +** if Target is not an Object: |
| 206710 | +** Target = {} # Ignore the contents and set it to an empty Object |
| 206711 | +** for each Name/Value pair in Patch: |
| 206712 | +** if Value is null: |
| 206713 | +** if Name exists in Target: |
| 206714 | +** remove the Name/Value pair from Target |
| 206715 | +** else: |
| 206716 | +** Target[Name] = MergePatch(Target[Name], Value) |
| 206717 | +** return Target |
| 206718 | +** else: |
| 206719 | +** return Patch |
| 206720 | +** |
| 206721 | +** Here is an equivalent algorithm restructured to show the actual |
| 206722 | +** implementation: |
| 206723 | +** |
| 206724 | +** 01 define MergePatch(Target, Patch): |
| 206725 | +** 02 if Patch is not an Object: |
| 206726 | +** 03 return Patch |
| 206727 | +** 04 else: // if Patch is an Object |
| 206728 | +** 05 if Target is not an Object: |
| 206729 | +** 06 Target = {} |
| 206730 | +** 07 for each Name/Value pair in Patch: |
| 206731 | +** 08 if Name exists in Target: |
| 206732 | +** 09 if Value is null: |
| 206733 | +** 10 remove the Name/Value pair from Target |
| 206734 | +** 11 else |
| 206735 | +** 12 Target[name] = MergePatch(Target[Name], Value) |
| 206736 | +** 13 else if Value is not NULL: |
| 206737 | +** 14 if Value is not an Object: |
| 206738 | +** 15 Target[name] = Value |
| 206739 | +** 16 else: |
| 206740 | +** 17 Target[name] = MergePatch('{}',value) |
| 206741 | +** 18 return Target |
| 206742 | +** | |
| 206743 | +** ^---- Line numbers referenced in comments in the implementation |
| 206744 | +*/ |
| 206745 | +static int jsonMergePatch( |
| 206746 | + JsonParse *pTarget, /* The JSON parser that contains the TARGET */ |
| 206747 | + u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */ |
| 206748 | + const JsonParse *pPatch, /* The PATCH */ |
| 206749 | + u32 iPatch /* Index of PATCH in pPatch->aBlob[] */ |
| 206750 | +){ |
| 206751 | + u8 x; /* Type of a single node */ |
| 206752 | + u32 n, sz=0; /* Return values from jsonbPayloadSize() */ |
| 206753 | + u32 iTCursor; /* Cursor position while scanning the target object */ |
| 206754 | + u32 iTStart; /* First label in the target object */ |
| 206755 | + u32 iTEndBE; /* Original first byte past end of target, before edit */ |
| 206756 | + u32 iTEnd; /* Current first byte past end of target */ |
| 206757 | + u8 eTLabel; /* Node type of the target label */ |
| 206758 | + u32 iTLabel = 0; /* Index of the label */ |
| 206759 | + u32 nTLabel = 0; /* Header size in bytes for the target label */ |
| 206760 | + u32 szTLabel = 0; /* Size of the target label payload */ |
| 206761 | + u32 iTValue = 0; /* Index of the target value */ |
| 206762 | + u32 nTValue = 0; /* Header size of the target value */ |
| 206763 | + u32 szTValue = 0; /* Payload size for the target value */ |
| 206764 | + |
| 206765 | + u32 iPCursor; /* Cursor position while scanning the patch */ |
| 206766 | + u32 iPEnd; /* First byte past the end of the patch */ |
| 206767 | + u8 ePLabel; /* Node type of the patch label */ |
| 206768 | + u32 iPLabel; /* Start of patch label */ |
| 206769 | + u32 nPLabel; /* Size of header on the patch label */ |
| 206770 | + u32 szPLabel; /* Payload size of the patch label */ |
| 206771 | + u32 iPValue; /* Start of patch value */ |
| 206772 | + u32 nPValue; /* Header size for the patch value */ |
| 206773 | + u32 szPValue; /* Payload size of the patch value */ |
| 206774 | + |
| 206775 | + assert( iTarget>=0 && iTarget<pTarget->nBlob ); |
| 206776 | + assert( iPatch>=0 && iPatch<pPatch->nBlob ); |
| 206777 | + x = pPatch->aBlob[iPatch] & 0x0f; |
| 206778 | + if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */ |
| 206779 | + u32 szPatch; /* Total size of the patch, header+payload */ |
| 206780 | + u32 szTarget; /* Total size of the target, header+payload */ |
| 206781 | + n = jsonbPayloadSize(pPatch, iPatch, &sz); |
| 206782 | + szPatch = n+sz; |
| 206783 | + sz = 0; |
| 206784 | + n = jsonbPayloadSize(pTarget, iTarget, &sz); |
| 206785 | + szTarget = n+sz; |
| 206786 | + jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch); |
| 206787 | + return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */ |
| 206788 | + } |
| 206789 | + x = pTarget->aBlob[iTarget] & 0x0f; |
| 206790 | + if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */ |
| 206791 | + n = jsonbPayloadSize(pTarget, iTarget, &sz); |
| 206792 | + jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0); |
| 206793 | + x = pTarget->aBlob[iTarget]; |
| 206794 | + pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT; |
| 206795 | + } |
| 206796 | + n = jsonbPayloadSize(pPatch, iPatch, &sz); |
| 206797 | + if( NEVER(n==0) ) return JSON_MERGE_BADPATCH; |
| 206798 | + iPCursor = iPatch+n; |
| 206799 | + iPEnd = iPCursor+sz; |
| 206800 | + n = jsonbPayloadSize(pTarget, iTarget, &sz); |
| 206801 | + if( NEVER(n==0) ) return JSON_MERGE_BADTARGET; |
| 206802 | + iTStart = iTarget+n; |
| 206803 | + iTEndBE = iTStart+sz; |
| 206804 | + |
| 206805 | + while( iPCursor<iPEnd ){ /* Algorithm line 07 */ |
| 206806 | + iPLabel = iPCursor; |
| 206807 | + ePLabel = pPatch->aBlob[iPCursor] & 0x0f; |
| 206808 | + if( ePLabel<JSONB_TEXT || ePLabel>JSONB_TEXTRAW ){ |
| 206809 | + return JSON_MERGE_BADPATCH; |
| 206810 | + } |
| 206811 | + nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel); |
| 206812 | + if( nPLabel==0 ) return JSON_MERGE_BADPATCH; |
| 206813 | + iPValue = iPCursor + nPLabel + szPLabel; |
| 206814 | + if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH; |
| 206815 | + nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue); |
| 206816 | + if( nPValue==0 ) return JSON_MERGE_BADPATCH; |
| 206817 | + iPCursor = iPValue + nPValue + szPValue; |
| 206818 | + if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH; |
| 206819 | + |
| 206820 | + iTCursor = iTStart; |
| 206821 | + iTEnd = iTEndBE + pTarget->delta; |
| 206822 | + while( iTCursor<iTEnd ){ |
| 206823 | + int isEqual; /* true if the patch and target labels match */ |
| 206824 | + iTLabel = iTCursor; |
| 206825 | + eTLabel = pTarget->aBlob[iTCursor] & 0x0f; |
| 206826 | + if( eTLabel<JSONB_TEXT || eTLabel>JSONB_TEXTRAW ){ |
| 206827 | + return JSON_MERGE_BADTARGET; |
| 206828 | + } |
| 206829 | + nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel); |
| 206830 | + if( nTLabel==0 ) return JSON_MERGE_BADTARGET; |
| 206831 | + iTValue = iTLabel + nTLabel + szTLabel; |
| 206832 | + if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET; |
| 206833 | + nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue); |
| 206834 | + if( nTValue==0 ) return JSON_MERGE_BADTARGET; |
| 206835 | + if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET; |
| 206836 | + isEqual = jsonLabelCompare( |
| 206837 | + (const char*)&pPatch->aBlob[iPLabel+nPLabel], |
| 206838 | + szPLabel, |
| 206839 | + (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW), |
| 206840 | + (const char*)&pTarget->aBlob[iTLabel+nTLabel], |
| 206841 | + szTLabel, |
| 206842 | + (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW)); |
| 206843 | + if( isEqual ) break; |
| 206844 | + iTCursor = iTValue + nTValue + szTValue; |
| 206845 | + } |
| 206846 | + x = pPatch->aBlob[iPValue] & 0x0f; |
| 206847 | + if( iTCursor<iTEnd ){ |
| 206848 | + /* A match was found. Algorithm line 08 */ |
| 206849 | + if( x==0 ){ |
| 206850 | + /* Patch value is NULL. Algorithm line 09 */ |
| 206851 | + jsonBlobEdit(pTarget, iTLabel, nTLabel+szTLabel+nTValue+szTValue, 0,0); |
| 206852 | + /* vvvvvv----- No OOM on a delete-only edit */ |
| 206853 | + if( NEVER(pTarget->oom) ) return JSON_MERGE_OOM; |
| 206854 | + }else{ |
| 206855 | + /* Algorithm line 12 */ |
| 206856 | + int rc, savedDelta = pTarget->delta; |
| 206857 | + pTarget->delta = 0; |
| 206858 | + rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue); |
| 206859 | + if( rc ) return rc; |
| 206860 | + pTarget->delta += savedDelta; |
| 206861 | + } |
| 206862 | + }else if( x>0 ){ /* Algorithm line 13 */ |
| 206863 | + /* No match and patch value is not NULL */ |
| 206864 | + u32 szNew = szPLabel+nPLabel; |
| 206865 | + if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */ |
| 206866 | + jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew); |
| 206867 | + if( pTarget->oom ) return JSON_MERGE_OOM; |
| 206868 | + memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); |
| 206869 | + memcpy(&pTarget->aBlob[iTEnd+szNew], |
| 206870 | + &pPatch->aBlob[iPValue], szPValue+nPValue); |
| 206871 | + }else{ |
| 206872 | + int rc, savedDelta; |
| 206873 | + jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1); |
| 206874 | + if( pTarget->oom ) return JSON_MERGE_OOM; |
| 206875 | + memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew); |
| 206876 | + pTarget->aBlob[iTEnd+szNew] = 0x00; |
| 206877 | + savedDelta = pTarget->delta; |
| 206878 | + pTarget->delta = 0; |
| 206879 | + rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue); |
| 206880 | + if( rc ) return rc; |
| 206881 | + pTarget->delta += savedDelta; |
| 206882 | + } |
| 206883 | + } |
| 206884 | + } |
| 206885 | + if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget); |
| 206886 | + return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; |
| 206887 | +} |
| 206888 | + |
| 205328 | 206889 | |
| 205329 | 206890 | /* |
| 205330 | 206891 | ** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON |
| 205331 | 206892 | ** object that is the result of running the RFC 7396 MergePatch() algorithm |
| 205332 | 206893 | ** on the two arguments. |
| | @@ -205334,32 +206895,31 @@ |
| 205334 | 206895 | static void jsonPatchFunc( |
| 205335 | 206896 | sqlite3_context *ctx, |
| 205336 | 206897 | int argc, |
| 205337 | 206898 | sqlite3_value **argv |
| 205338 | 206899 | ){ |
| 205339 | | - JsonParse *pX; /* The JSON that is being patched */ |
| 205340 | | - JsonParse *pY; /* The patch */ |
| 205341 | | - JsonNode *pResult; /* The result of the merge */ |
| 206900 | + JsonParse *pTarget; /* The TARGET */ |
| 206901 | + JsonParse *pPatch; /* The PATCH */ |
| 206902 | + int rc; /* Result code */ |
| 205342 | 206903 | |
| 205343 | 206904 | UNUSED_PARAMETER(argc); |
| 205344 | | - pX = jsonParseCached(ctx, argv[0], ctx, 1); |
| 205345 | | - if( pX==0 ) return; |
| 205346 | | - assert( pX->hasMod==0 ); |
| 205347 | | - pX->hasMod = 1; |
| 205348 | | - pY = jsonParseCached(ctx, argv[1], ctx, 1); |
| 205349 | | - if( pY==0 ) return; |
| 205350 | | - pX->useMod = 1; |
| 205351 | | - pY->useMod = 1; |
| 205352 | | - pResult = jsonMergePatch(pX, 0, pY->aNode); |
| 205353 | | - assert( pResult!=0 || pX->oom ); |
| 205354 | | - if( pResult && pX->oom==0 ){ |
| 205355 | | - jsonDebugPrintParse(pX); |
| 205356 | | - jsonDebugPrintNode(pResult); |
| 205357 | | - jsonReturnJson(pX, pResult, ctx, 0, 0); |
| 205358 | | - }else{ |
| 205359 | | - sqlite3_result_error_nomem(ctx); |
| 205360 | | - } |
| 206905 | + assert( argc==2 ); |
| 206906 | + pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE); |
| 206907 | + if( pTarget==0 ) return; |
| 206908 | + pPatch = jsonParseFuncArg(ctx, argv[1], 0); |
| 206909 | + if( pPatch ){ |
| 206910 | + rc = jsonMergePatch(pTarget, 0, pPatch, 0); |
| 206911 | + if( rc==JSON_MERGE_OK ){ |
| 206912 | + jsonReturnParse(ctx, pTarget); |
| 206913 | + }else if( rc==JSON_MERGE_OOM ){ |
| 206914 | + sqlite3_result_error_nomem(ctx); |
| 206915 | + }else{ |
| 206916 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 206917 | + } |
| 206918 | + jsonParseFree(pPatch); |
| 206919 | + } |
| 206920 | + jsonParseFree(pTarget); |
| 205361 | 206921 | } |
| 205362 | 206922 | |
| 205363 | 206923 | |
| 205364 | 206924 | /* |
| 205365 | 206925 | ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON |
| | @@ -205379,27 +206939,27 @@ |
| 205379 | 206939 | if( argc&1 ){ |
| 205380 | 206940 | sqlite3_result_error(ctx, "json_object() requires an even number " |
| 205381 | 206941 | "of arguments", -1); |
| 205382 | 206942 | return; |
| 205383 | 206943 | } |
| 205384 | | - jsonInit(&jx, ctx); |
| 206944 | + jsonStringInit(&jx, ctx); |
| 205385 | 206945 | jsonAppendChar(&jx, '{'); |
| 205386 | 206946 | for(i=0; i<argc; i+=2){ |
| 205387 | 206947 | if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){ |
| 205388 | 206948 | sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1); |
| 205389 | | - jsonReset(&jx); |
| 206949 | + jsonStringReset(&jx); |
| 205390 | 206950 | return; |
| 205391 | 206951 | } |
| 205392 | 206952 | jsonAppendSeparator(&jx); |
| 205393 | 206953 | z = (const char*)sqlite3_value_text(argv[i]); |
| 205394 | | - n = (u32)sqlite3_value_bytes(argv[i]); |
| 206954 | + n = sqlite3_value_bytes(argv[i]); |
| 205395 | 206955 | jsonAppendString(&jx, z, n); |
| 205396 | 206956 | jsonAppendChar(&jx, ':'); |
| 205397 | | - jsonAppendValue(&jx, argv[i+1]); |
| 206957 | + jsonAppendSqlValue(&jx, argv[i+1]); |
| 205398 | 206958 | } |
| 205399 | 206959 | jsonAppendChar(&jx, '}'); |
| 205400 | | - jsonResult(&jx); |
| 206960 | + jsonReturnString(&jx, 0, 0); |
| 205401 | 206961 | sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
| 205402 | 206962 | } |
| 205403 | 206963 | |
| 205404 | 206964 | |
| 205405 | 206965 | /* |
| | @@ -205411,124 +206971,54 @@ |
| 205411 | 206971 | static void jsonRemoveFunc( |
| 205412 | 206972 | sqlite3_context *ctx, |
| 205413 | 206973 | int argc, |
| 205414 | 206974 | sqlite3_value **argv |
| 205415 | 206975 | ){ |
| 205416 | | - JsonParse *pParse; /* The parse */ |
| 205417 | | - JsonNode *pNode; |
| 205418 | | - const char *zPath; |
| 205419 | | - u32 i; |
| 206976 | + JsonParse *p; /* The parse */ |
| 206977 | + const char *zPath = 0; /* Path of element to be removed */ |
| 206978 | + int i; /* Loop counter */ |
| 206979 | + u32 rc; /* Subroutine return code */ |
| 205420 | 206980 | |
| 205421 | 206981 | if( argc<1 ) return; |
| 205422 | | - pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); |
| 205423 | | - if( pParse==0 ) return; |
| 205424 | | - for(i=1; i<(u32)argc; i++){ |
| 206982 | + p = jsonParseFuncArg(ctx, argv[0], argc>1 ? JSON_EDITABLE : 0); |
| 206983 | + if( p==0 ) return; |
| 206984 | + for(i=1; i<argc; i++){ |
| 205425 | 206985 | zPath = (const char*)sqlite3_value_text(argv[i]); |
| 205426 | | - if( zPath==0 ) goto remove_done; |
| 205427 | | - pNode = jsonLookup(pParse, zPath, 0, ctx); |
| 205428 | | - if( pParse->nErr ) goto remove_done; |
| 205429 | | - if( pNode ){ |
| 205430 | | - pNode->jnFlags |= JNODE_REMOVE; |
| 205431 | | - pParse->hasMod = 1; |
| 205432 | | - pParse->useMod = 1; |
| 205433 | | - } |
| 205434 | | - } |
| 205435 | | - if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){ |
| 205436 | | - jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); |
| 205437 | | - } |
| 205438 | | -remove_done: |
| 205439 | | - jsonDebugPrintParse(p); |
| 205440 | | -} |
| 205441 | | - |
| 205442 | | -/* |
| 205443 | | -** Substitute the value at iNode with the pValue parameter. |
| 205444 | | -*/ |
| 205445 | | -static void jsonReplaceNode( |
| 205446 | | - sqlite3_context *pCtx, |
| 205447 | | - JsonParse *p, |
| 205448 | | - int iNode, |
| 205449 | | - sqlite3_value *pValue |
| 205450 | | -){ |
| 205451 | | - int idx = jsonParseAddSubstNode(p, iNode); |
| 205452 | | - if( idx<=0 ){ |
| 205453 | | - assert( p->oom ); |
| 205454 | | - return; |
| 205455 | | - } |
| 205456 | | - switch( sqlite3_value_type(pValue) ){ |
| 205457 | | - case SQLITE_NULL: { |
| 205458 | | - jsonParseAddNode(p, JSON_NULL, 0, 0); |
| 205459 | | - break; |
| 205460 | | - } |
| 205461 | | - case SQLITE_FLOAT: { |
| 205462 | | - char *z = sqlite3_mprintf("%!0.15g", sqlite3_value_double(pValue)); |
| 205463 | | - int n; |
| 205464 | | - if( z==0 ){ |
| 205465 | | - p->oom = 1; |
| 205466 | | - break; |
| 205467 | | - } |
| 205468 | | - n = sqlite3Strlen30(z); |
| 205469 | | - jsonParseAddNode(p, JSON_REAL, n, z); |
| 205470 | | - jsonParseAddCleanup(p, sqlite3_free, z); |
| 205471 | | - break; |
| 205472 | | - } |
| 205473 | | - case SQLITE_INTEGER: { |
| 205474 | | - char *z = sqlite3_mprintf("%lld", sqlite3_value_int64(pValue)); |
| 205475 | | - int n; |
| 205476 | | - if( z==0 ){ |
| 205477 | | - p->oom = 1; |
| 205478 | | - break; |
| 205479 | | - } |
| 205480 | | - n = sqlite3Strlen30(z); |
| 205481 | | - jsonParseAddNode(p, JSON_INT, n, z); |
| 205482 | | - jsonParseAddCleanup(p, sqlite3_free, z); |
| 205483 | | - |
| 205484 | | - break; |
| 205485 | | - } |
| 205486 | | - case SQLITE_TEXT: { |
| 205487 | | - const char *z = (const char*)sqlite3_value_text(pValue); |
| 205488 | | - u32 n = (u32)sqlite3_value_bytes(pValue); |
| 205489 | | - if( z==0 ){ |
| 205490 | | - p->oom = 1; |
| 205491 | | - break; |
| 205492 | | - } |
| 205493 | | - if( sqlite3_value_subtype(pValue)!=JSON_SUBTYPE ){ |
| 205494 | | - char *zCopy = sqlite3_malloc64( n+1 ); |
| 205495 | | - int k; |
| 205496 | | - if( zCopy ){ |
| 205497 | | - memcpy(zCopy, z, n); |
| 205498 | | - zCopy[n] = 0; |
| 205499 | | - jsonParseAddCleanup(p, sqlite3_free, zCopy); |
| 205500 | | - }else{ |
| 205501 | | - p->oom = 1; |
| 205502 | | - sqlite3_result_error_nomem(pCtx); |
| 205503 | | - } |
| 205504 | | - k = jsonParseAddNode(p, JSON_STRING, n, zCopy); |
| 205505 | | - assert( k>0 || p->oom ); |
| 205506 | | - if( p->oom==0 ) p->aNode[k].jnFlags |= JNODE_RAW; |
| 205507 | | - }else{ |
| 205508 | | - JsonParse *pPatch = jsonParseCached(pCtx, pValue, pCtx, 1); |
| 205509 | | - if( pPatch==0 ){ |
| 205510 | | - p->oom = 1; |
| 205511 | | - break; |
| 205512 | | - } |
| 205513 | | - jsonParseAddNodeArray(p, pPatch->aNode, pPatch->nNode); |
| 205514 | | - /* The nodes copied out of pPatch and into p likely contain |
| 205515 | | - ** u.zJContent pointers into pPatch->zJson. So preserve the |
| 205516 | | - ** content of pPatch until p is destroyed. */ |
| 205517 | | - assert( pPatch->nJPRef>=1 ); |
| 205518 | | - pPatch->nJPRef++; |
| 205519 | | - jsonParseAddCleanup(p, (void(*)(void*))jsonParseFree, pPatch); |
| 205520 | | - } |
| 205521 | | - break; |
| 205522 | | - } |
| 205523 | | - default: { |
| 205524 | | - jsonParseAddNode(p, JSON_NULL, 0, 0); |
| 205525 | | - sqlite3_result_error(pCtx, "JSON cannot hold BLOB values", -1); |
| 205526 | | - p->nErr++; |
| 205527 | | - break; |
| 205528 | | - } |
| 205529 | | - } |
| 206986 | + if( zPath==0 ){ |
| 206987 | + goto json_remove_done; |
| 206988 | + } |
| 206989 | + if( zPath[0]!='$' ){ |
| 206990 | + goto json_remove_patherror; |
| 206991 | + } |
| 206992 | + if( zPath[1]==0 ){ |
| 206993 | + /* json_remove(j,'$') returns NULL */ |
| 206994 | + goto json_remove_done; |
| 206995 | + } |
| 206996 | + p->eEdit = JEDIT_DEL; |
| 206997 | + p->delta = 0; |
| 206998 | + rc = jsonLookupStep(p, 0, zPath+1, 0); |
| 206999 | + if( JSON_LOOKUP_ISERROR(rc) ){ |
| 207000 | + if( rc==JSON_LOOKUP_NOTFOUND ){ |
| 207001 | + continue; /* No-op */ |
| 207002 | + }else if( rc==JSON_LOOKUP_PATHERROR ){ |
| 207003 | + jsonBadPathError(ctx, zPath); |
| 207004 | + }else{ |
| 207005 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 207006 | + } |
| 207007 | + goto json_remove_done; |
| 207008 | + } |
| 207009 | + } |
| 207010 | + jsonReturnParse(ctx, p); |
| 207011 | + jsonParseFree(p); |
| 207012 | + return; |
| 207013 | + |
| 207014 | +json_remove_patherror: |
| 207015 | + jsonBadPathError(ctx, zPath); |
| 207016 | + |
| 207017 | +json_remove_done: |
| 207018 | + jsonParseFree(p); |
| 207019 | + return; |
| 205530 | 207020 | } |
| 205531 | 207021 | |
| 205532 | 207022 | /* |
| 205533 | 207023 | ** json_replace(JSON, PATH, VALUE, ...) |
| 205534 | 207024 | ** |
| | @@ -205538,36 +207028,16 @@ |
| 205538 | 207028 | static void jsonReplaceFunc( |
| 205539 | 207029 | sqlite3_context *ctx, |
| 205540 | 207030 | int argc, |
| 205541 | 207031 | sqlite3_value **argv |
| 205542 | 207032 | ){ |
| 205543 | | - JsonParse *pParse; /* The parse */ |
| 205544 | | - JsonNode *pNode; |
| 205545 | | - const char *zPath; |
| 205546 | | - u32 i; |
| 205547 | | - |
| 205548 | 207033 | if( argc<1 ) return; |
| 205549 | 207034 | if( (argc&1)==0 ) { |
| 205550 | 207035 | jsonWrongNumArgs(ctx, "replace"); |
| 205551 | 207036 | return; |
| 205552 | 207037 | } |
| 205553 | | - pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); |
| 205554 | | - if( pParse==0 ) return; |
| 205555 | | - pParse->nJPRef++; |
| 205556 | | - for(i=1; i<(u32)argc; i+=2){ |
| 205557 | | - zPath = (const char*)sqlite3_value_text(argv[i]); |
| 205558 | | - pParse->useMod = 1; |
| 205559 | | - pNode = jsonLookup(pParse, zPath, 0, ctx); |
| 205560 | | - if( pParse->nErr ) goto replace_err; |
| 205561 | | - if( pNode ){ |
| 205562 | | - jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); |
| 205563 | | - } |
| 205564 | | - } |
| 205565 | | - jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); |
| 205566 | | -replace_err: |
| 205567 | | - jsonDebugPrintParse(pParse); |
| 205568 | | - jsonParseFree(pParse); |
| 207038 | + jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL); |
| 205569 | 207039 | } |
| 205570 | 207040 | |
| 205571 | 207041 | |
| 205572 | 207042 | /* |
| 205573 | 207043 | ** json_set(JSON, PATH, VALUE, ...) |
| | @@ -205584,43 +207054,20 @@ |
| 205584 | 207054 | static void jsonSetFunc( |
| 205585 | 207055 | sqlite3_context *ctx, |
| 205586 | 207056 | int argc, |
| 205587 | 207057 | sqlite3_value **argv |
| 205588 | 207058 | ){ |
| 205589 | | - JsonParse *pParse; /* The parse */ |
| 205590 | | - JsonNode *pNode; |
| 205591 | | - const char *zPath; |
| 205592 | | - u32 i; |
| 205593 | | - int bApnd; |
| 205594 | | - int bIsSet = sqlite3_user_data(ctx)!=0; |
| 207059 | + |
| 207060 | + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 207061 | + int bIsSet = (flags&JSON_ISSET)!=0; |
| 205595 | 207062 | |
| 205596 | 207063 | if( argc<1 ) return; |
| 205597 | 207064 | if( (argc&1)==0 ) { |
| 205598 | 207065 | jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); |
| 205599 | 207066 | return; |
| 205600 | 207067 | } |
| 205601 | | - pParse = jsonParseCached(ctx, argv[0], ctx, argc>1); |
| 205602 | | - if( pParse==0 ) return; |
| 205603 | | - pParse->nJPRef++; |
| 205604 | | - for(i=1; i<(u32)argc; i+=2){ |
| 205605 | | - zPath = (const char*)sqlite3_value_text(argv[i]); |
| 205606 | | - bApnd = 0; |
| 205607 | | - pParse->useMod = 1; |
| 205608 | | - pNode = jsonLookup(pParse, zPath, &bApnd, ctx); |
| 205609 | | - if( pParse->oom ){ |
| 205610 | | - sqlite3_result_error_nomem(ctx); |
| 205611 | | - goto jsonSetDone; |
| 205612 | | - }else if( pParse->nErr ){ |
| 205613 | | - goto jsonSetDone; |
| 205614 | | - }else if( pNode && (bApnd || bIsSet) ){ |
| 205615 | | - jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); |
| 205616 | | - } |
| 205617 | | - } |
| 205618 | | - jsonDebugPrintParse(pParse); |
| 205619 | | - jsonReturnJson(pParse, pParse->aNode, ctx, 1, 0); |
| 205620 | | -jsonSetDone: |
| 205621 | | - jsonParseFree(pParse); |
| 207068 | + jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); |
| 205622 | 207069 | } |
| 205623 | 207070 | |
| 205624 | 207071 | /* |
| 205625 | 207072 | ** json_type(JSON) |
| 205626 | 207073 | ** json_type(JSON, PATH) |
| | @@ -205632,110 +207079,221 @@ |
| 205632 | 207079 | sqlite3_context *ctx, |
| 205633 | 207080 | int argc, |
| 205634 | 207081 | sqlite3_value **argv |
| 205635 | 207082 | ){ |
| 205636 | 207083 | JsonParse *p; /* The parse */ |
| 205637 | | - const char *zPath; |
| 205638 | | - JsonNode *pNode; |
| 207084 | + const char *zPath = 0; |
| 207085 | + u32 i; |
| 205639 | 207086 | |
| 205640 | | - p = jsonParseCached(ctx, argv[0], ctx, 0); |
| 207087 | + p = jsonParseFuncArg(ctx, argv[0], 0); |
| 205641 | 207088 | if( p==0 ) return; |
| 205642 | 207089 | if( argc==2 ){ |
| 205643 | 207090 | zPath = (const char*)sqlite3_value_text(argv[1]); |
| 205644 | | - pNode = jsonLookup(p, zPath, 0, ctx); |
| 207091 | + if( zPath==0 ) goto json_type_done; |
| 207092 | + if( zPath[0]!='$' ){ |
| 207093 | + jsonBadPathError(ctx, zPath); |
| 207094 | + goto json_type_done; |
| 207095 | + } |
| 207096 | + i = jsonLookupStep(p, 0, zPath+1, 0); |
| 207097 | + if( JSON_LOOKUP_ISERROR(i) ){ |
| 207098 | + if( i==JSON_LOOKUP_NOTFOUND ){ |
| 207099 | + /* no-op */ |
| 207100 | + }else if( i==JSON_LOOKUP_PATHERROR ){ |
| 207101 | + jsonBadPathError(ctx, zPath); |
| 207102 | + }else{ |
| 207103 | + sqlite3_result_error(ctx, "malformed JSON", -1); |
| 207104 | + } |
| 207105 | + goto json_type_done; |
| 207106 | + } |
| 205645 | 207107 | }else{ |
| 205646 | | - pNode = p->aNode; |
| 207108 | + i = 0; |
| 205647 | 207109 | } |
| 205648 | | - if( pNode ){ |
| 205649 | | - sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); |
| 205650 | | - } |
| 207110 | + sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC); |
| 207111 | +json_type_done: |
| 207112 | + jsonParseFree(p); |
| 205651 | 207113 | } |
| 205652 | 207114 | |
| 205653 | 207115 | /* |
| 205654 | 207116 | ** json_valid(JSON) |
| 207117 | +** json_valid(JSON, FLAGS) |
| 205655 | 207118 | ** |
| 205656 | | -** Return 1 if JSON is a well-formed canonical JSON string according |
| 205657 | | -** to RFC-7159. Return 0 otherwise. |
| 207119 | +** Check the JSON argument to see if it is well-formed. The FLAGS argument |
| 207120 | +** encodes the various constraints on what is meant by "well-formed": |
| 207121 | +** |
| 207122 | +** 0x01 Canonical RFC-8259 JSON text |
| 207123 | +** 0x02 JSON text with optional JSON-5 extensions |
| 207124 | +** 0x04 Superficially appears to be JSONB |
| 207125 | +** 0x08 Strictly well-formed JSONB |
| 207126 | +** |
| 207127 | +** If the FLAGS argument is omitted, it defaults to 1. Useful values for |
| 207128 | +** FLAGS include: |
| 207129 | +** |
| 207130 | +** 1 Strict canonical JSON text |
| 207131 | +** 2 JSON text perhaps with JSON-5 extensions |
| 207132 | +** 4 Superficially appears to be JSONB |
| 207133 | +** 5 Canonical JSON text or superficial JSONB |
| 207134 | +** 6 JSON-5 text or superficial JSONB |
| 207135 | +** 8 Strict JSONB |
| 207136 | +** 9 Canonical JSON text or strict JSONB |
| 207137 | +** 10 JSON-5 text or strict JSONB |
| 207138 | +** |
| 207139 | +** Other flag combinations are redundant. For example, every canonical |
| 207140 | +** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3 |
| 207141 | +** are the same. Similarly, any input that passes a strict JSONB validation |
| 207142 | +** will also pass the superficial validation so 12 through 15 are the same |
| 207143 | +** as 8 through 11 respectively. |
| 207144 | +** |
| 207145 | +** This routine runs in linear time to validate text and when doing strict |
| 207146 | +** JSONB validation. Superficial JSONB validation is constant time, |
| 207147 | +** assuming the BLOB is already in memory. The performance advantage |
| 207148 | +** of superficial JSONB validation is why that option is provided. |
| 207149 | +** Application developers can choose to do fast superficial validation or |
| 207150 | +** slower strict validation, according to their specific needs. |
| 207151 | +** |
| 207152 | +** Only the lower four bits of the FLAGS argument are currently used. |
| 207153 | +** Higher bits are reserved for future expansion. To facilitate |
| 207154 | +** compatibility, the current implementation raises an error if any bit |
| 207155 | +** in FLAGS is set other than the lower four bits. |
| 207156 | +** |
| 207157 | +** The original circa 2015 implementation of the JSON routines in |
| 207158 | +** SQLite only supported canonical RFC-8259 JSON text and the json_valid() |
| 207159 | +** function only accepted one argument. That is why the default value |
| 207160 | +** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only |
| 207161 | +** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS |
| 207162 | +** argument was added when the JSON routines were extended to support |
| 207163 | +** JSON5-like extensions and binary JSONB stored in BLOBs. |
| 207164 | +** |
| 207165 | +** Return Values: |
| 207166 | +** |
| 207167 | +** * Raise an error if FLAGS is outside the range of 1 to 15. |
| 207168 | +** * Return NULL if the input is NULL |
| 207169 | +** * Return 1 if the input is well-formed. |
| 207170 | +** * Return 0 if the input is not well-formed. |
| 205658 | 207171 | */ |
| 205659 | 207172 | static void jsonValidFunc( |
| 205660 | 207173 | sqlite3_context *ctx, |
| 205661 | 207174 | int argc, |
| 205662 | 207175 | sqlite3_value **argv |
| 205663 | 207176 | ){ |
| 205664 | 207177 | JsonParse *p; /* The parse */ |
| 205665 | | - UNUSED_PARAMETER(argc); |
| 205666 | | - if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ |
| 207178 | + u8 flags = 1; |
| 207179 | + u8 res = 0; |
| 207180 | + if( argc==2 ){ |
| 207181 | + i64 f = sqlite3_value_int64(argv[1]); |
| 207182 | + if( f<1 || f>15 ){ |
| 207183 | + sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be" |
| 207184 | + " between 1 and 15", -1); |
| 207185 | + return; |
| 207186 | + } |
| 207187 | + flags = f & 0x0f; |
| 207188 | + } |
| 207189 | + switch( sqlite3_value_type(argv[0]) ){ |
| 207190 | + case SQLITE_NULL: { |
| 205667 | 207191 | #ifdef SQLITE_LEGACY_JSON_VALID |
| 205668 | | - /* Incorrect legacy behavior was to return FALSE for a NULL input */ |
| 205669 | | - sqlite3_result_int(ctx, 0); |
| 207192 | + /* Incorrect legacy behavior was to return FALSE for a NULL input */ |
| 207193 | + sqlite3_result_int(ctx, 0); |
| 205670 | 207194 | #endif |
| 205671 | | - return; |
| 205672 | | - } |
| 205673 | | - p = jsonParseCached(ctx, argv[0], 0, 0); |
| 205674 | | - if( p==0 || p->oom ){ |
| 205675 | | - sqlite3_result_error_nomem(ctx); |
| 205676 | | - sqlite3_free(p); |
| 205677 | | - }else{ |
| 205678 | | - sqlite3_result_int(ctx, p->nErr==0 && (p->hasNonstd==0 || p->useMod)); |
| 205679 | | - if( p->nErr ) jsonParseFree(p); |
| 205680 | | - } |
| 207195 | + return; |
| 207196 | + } |
| 207197 | + case SQLITE_BLOB: { |
| 207198 | + if( (flags & 0x0c)!=0 && jsonFuncArgMightBeBinary(argv[0]) ){ |
| 207199 | + if( flags & 0x04 ){ |
| 207200 | + /* Superficial checking only - accomplished by the |
| 207201 | + ** jsonFuncArgMightBeBinary() call above. */ |
| 207202 | + res = 1; |
| 207203 | + }else{ |
| 207204 | + /* Strict checking. Check by translating BLOB->TEXT->BLOB. If |
| 207205 | + ** no errors occur, call that a "strict check". */ |
| 207206 | + JsonParse px; |
| 207207 | + u32 iErr; |
| 207208 | + memset(&px, 0, sizeof(px)); |
| 207209 | + px.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 207210 | + px.nBlob = sqlite3_value_bytes(argv[0]); |
| 207211 | + iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); |
| 207212 | + res = iErr==0; |
| 207213 | + } |
| 207214 | + } |
| 207215 | + break; |
| 207216 | + } |
| 207217 | + default: { |
| 207218 | + JsonParse px; |
| 207219 | + if( (flags & 0x3)==0 ) break; |
| 207220 | + memset(&px, 0, sizeof(px)); |
| 207221 | + |
| 207222 | + p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR); |
| 207223 | + if( p ){ |
| 207224 | + if( p->oom ){ |
| 207225 | + sqlite3_result_error_nomem(ctx); |
| 207226 | + }else if( p->nErr ){ |
| 207227 | + /* no-op */ |
| 207228 | + }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){ |
| 207229 | + res = 1; |
| 207230 | + } |
| 207231 | + jsonParseFree(p); |
| 207232 | + }else{ |
| 207233 | + sqlite3_result_error_nomem(ctx); |
| 207234 | + } |
| 207235 | + break; |
| 207236 | + } |
| 207237 | + } |
| 207238 | + sqlite3_result_int(ctx, res); |
| 205681 | 207239 | } |
| 205682 | 207240 | |
| 205683 | 207241 | /* |
| 205684 | 207242 | ** json_error_position(JSON) |
| 205685 | 207243 | ** |
| 205686 | | -** If the argument is not an interpretable JSON string, then return the 1-based |
| 205687 | | -** character position at which the parser first recognized that the input |
| 205688 | | -** was in error. The left-most character is 1. If the string is valid |
| 205689 | | -** JSON, then return 0. |
| 205690 | | -** |
| 205691 | | -** Note that json_valid() is only true for strictly conforming canonical JSON. |
| 205692 | | -** But this routine returns zero if the input contains extension. Thus: |
| 205693 | | -** |
| 205694 | | -** (1) If the input X is strictly conforming canonical JSON: |
| 205695 | | -** |
| 205696 | | -** json_valid(X) returns true |
| 205697 | | -** json_error_position(X) returns 0 |
| 205698 | | -** |
| 205699 | | -** (2) If the input X is JSON but it includes extension (such as JSON5) that |
| 205700 | | -** are not part of RFC-8259: |
| 205701 | | -** |
| 205702 | | -** json_valid(X) returns false |
| 205703 | | -** json_error_position(X) return 0 |
| 205704 | | -** |
| 205705 | | -** (3) If the input X cannot be interpreted as JSON even taking extensions |
| 205706 | | -** into account: |
| 205707 | | -** |
| 205708 | | -** json_valid(X) return false |
| 205709 | | -** json_error_position(X) returns 1 or more |
| 207244 | +** If the argument is NULL, return NULL |
| 207245 | +** |
| 207246 | +** If the argument is BLOB, do a full validity check and return non-zero |
| 207247 | +** if the check fails. The return value is the approximate 1-based offset |
| 207248 | +** to the byte of the element that contains the first error. |
| 207249 | +** |
| 207250 | +** Otherwise interpret the argument is TEXT (even if it is numeric) and |
| 207251 | +** return the 1-based character position for where the parser first recognized |
| 207252 | +** that the input was not valid JSON, or return 0 if the input text looks |
| 207253 | +** ok. JSON-5 extensions are accepted. |
| 205710 | 207254 | */ |
| 205711 | 207255 | static void jsonErrorFunc( |
| 205712 | 207256 | sqlite3_context *ctx, |
| 205713 | 207257 | int argc, |
| 205714 | 207258 | sqlite3_value **argv |
| 205715 | 207259 | ){ |
| 205716 | | - JsonParse *p; /* The parse */ |
| 207260 | + i64 iErrPos = 0; /* Error position to be returned */ |
| 207261 | + JsonParse s; |
| 207262 | + |
| 207263 | + assert( argc==1 ); |
| 205717 | 207264 | UNUSED_PARAMETER(argc); |
| 205718 | | - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; |
| 205719 | | - p = jsonParseCached(ctx, argv[0], 0, 0); |
| 205720 | | - if( p==0 || p->oom ){ |
| 207265 | + memset(&s, 0, sizeof(s)); |
| 207266 | + if( jsonFuncArgMightBeBinary(argv[0]) ){ |
| 207267 | + s.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 207268 | + s.nBlob = sqlite3_value_bytes(argv[0]); |
| 207269 | + iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); |
| 207270 | + }else{ |
| 207271 | + s.zJson = (char*)sqlite3_value_text(argv[0]); |
| 207272 | + if( s.zJson==0 ) return; /* NULL input or OOM */ |
| 207273 | + s.nJson = sqlite3_value_bytes(argv[0]); |
| 207274 | + if( jsonConvertTextToBlob(&s,0) ){ |
| 207275 | + if( s.oom ){ |
| 207276 | + iErrPos = -1; |
| 207277 | + }else{ |
| 207278 | + /* Convert byte-offset s.iErr into a character offset */ |
| 207279 | + u32 k; |
| 207280 | + assert( s.zJson!=0 ); /* Because s.oom is false */ |
| 207281 | + for(k=0; k<s.iErr && ALWAYS(s.zJson[k]); k++){ |
| 207282 | + if( (s.zJson[k] & 0xc0)!=0x80 ) iErrPos++; |
| 207283 | + } |
| 207284 | + iErrPos++; |
| 207285 | + } |
| 207286 | + } |
| 207287 | + } |
| 207288 | + jsonParseReset(&s); |
| 207289 | + if( iErrPos<0 ){ |
| 205721 | 207290 | sqlite3_result_error_nomem(ctx); |
| 205722 | | - sqlite3_free(p); |
| 205723 | | - }else if( p->nErr==0 ){ |
| 205724 | | - sqlite3_result_int(ctx, 0); |
| 205725 | | - }else{ |
| 205726 | | - int n = 1; |
| 205727 | | - u32 i; |
| 205728 | | - const char *z = (const char*)sqlite3_value_text(argv[0]); |
| 205729 | | - for(i=0; i<p->iErr && ALWAYS(z[i]); i++){ |
| 205730 | | - if( (z[i]&0xc0)!=0x80 ) n++; |
| 205731 | | - } |
| 205732 | | - sqlite3_result_int(ctx, n); |
| 205733 | | - jsonParseFree(p); |
| 205734 | | - } |
| 205735 | | -} |
| 205736 | | - |
| 207291 | + }else{ |
| 207292 | + sqlite3_result_int64(ctx, iErrPos); |
| 207293 | + } |
| 207294 | +} |
| 205737 | 207295 | |
| 205738 | 207296 | /**************************************************************************** |
| 205739 | 207297 | ** Aggregate SQL function implementations |
| 205740 | 207298 | ****************************************************************************/ |
| 205741 | 207299 | /* |
| | @@ -205751,28 +207309,38 @@ |
| 205751 | 207309 | JsonString *pStr; |
| 205752 | 207310 | UNUSED_PARAMETER(argc); |
| 205753 | 207311 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); |
| 205754 | 207312 | if( pStr ){ |
| 205755 | 207313 | if( pStr->zBuf==0 ){ |
| 205756 | | - jsonInit(pStr, ctx); |
| 207314 | + jsonStringInit(pStr, ctx); |
| 205757 | 207315 | jsonAppendChar(pStr, '['); |
| 205758 | 207316 | }else if( pStr->nUsed>1 ){ |
| 205759 | 207317 | jsonAppendChar(pStr, ','); |
| 205760 | 207318 | } |
| 205761 | 207319 | pStr->pCtx = ctx; |
| 205762 | | - jsonAppendValue(pStr, argv[0]); |
| 207320 | + jsonAppendSqlValue(pStr, argv[0]); |
| 205763 | 207321 | } |
| 205764 | 207322 | } |
| 205765 | 207323 | static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ |
| 205766 | 207324 | JsonString *pStr; |
| 205767 | 207325 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); |
| 205768 | 207326 | if( pStr ){ |
| 207327 | + int flags; |
| 205769 | 207328 | pStr->pCtx = ctx; |
| 205770 | 207329 | jsonAppendChar(pStr, ']'); |
| 205771 | | - if( pStr->bErr ){ |
| 205772 | | - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 205773 | | - assert( pStr->bStatic ); |
| 207330 | + flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 207331 | + if( pStr->eErr ){ |
| 207332 | + jsonReturnString(pStr, 0, 0); |
| 207333 | + return; |
| 207334 | + }else if( flags & JSON_BLOB ){ |
| 207335 | + jsonReturnStringAsBlob(pStr); |
| 207336 | + if( isFinal ){ |
| 207337 | + if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); |
| 207338 | + }else{ |
| 207339 | + pStr->nUsed--; |
| 207340 | + } |
| 207341 | + return; |
| 205774 | 207342 | }else if( isFinal ){ |
| 205775 | 207343 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, |
| 205776 | 207344 | pStr->bStatic ? SQLITE_TRANSIENT : |
| 205777 | 207345 | sqlite3RCStrUnref); |
| 205778 | 207346 | pStr->bStatic = 1; |
| | @@ -205857,31 +207425,42 @@ |
| 205857 | 207425 | u32 n; |
| 205858 | 207426 | UNUSED_PARAMETER(argc); |
| 205859 | 207427 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); |
| 205860 | 207428 | if( pStr ){ |
| 205861 | 207429 | if( pStr->zBuf==0 ){ |
| 205862 | | - jsonInit(pStr, ctx); |
| 207430 | + jsonStringInit(pStr, ctx); |
| 205863 | 207431 | jsonAppendChar(pStr, '{'); |
| 205864 | 207432 | }else if( pStr->nUsed>1 ){ |
| 205865 | 207433 | jsonAppendChar(pStr, ','); |
| 205866 | 207434 | } |
| 205867 | 207435 | pStr->pCtx = ctx; |
| 205868 | 207436 | z = (const char*)sqlite3_value_text(argv[0]); |
| 205869 | | - n = (u32)sqlite3_value_bytes(argv[0]); |
| 207437 | + n = sqlite3Strlen30(z); |
| 205870 | 207438 | jsonAppendString(pStr, z, n); |
| 205871 | 207439 | jsonAppendChar(pStr, ':'); |
| 205872 | | - jsonAppendValue(pStr, argv[1]); |
| 207440 | + jsonAppendSqlValue(pStr, argv[1]); |
| 205873 | 207441 | } |
| 205874 | 207442 | } |
| 205875 | 207443 | static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ |
| 205876 | 207444 | JsonString *pStr; |
| 205877 | 207445 | pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); |
| 205878 | 207446 | if( pStr ){ |
| 207447 | + int flags; |
| 205879 | 207448 | jsonAppendChar(pStr, '}'); |
| 205880 | | - if( pStr->bErr ){ |
| 205881 | | - if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 205882 | | - assert( pStr->bStatic ); |
| 207449 | + pStr->pCtx = ctx; |
| 207450 | + flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); |
| 207451 | + if( pStr->eErr ){ |
| 207452 | + jsonReturnString(pStr, 0, 0); |
| 207453 | + return; |
| 207454 | + }else if( flags & JSON_BLOB ){ |
| 207455 | + jsonReturnStringAsBlob(pStr); |
| 207456 | + if( isFinal ){ |
| 207457 | + if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf); |
| 207458 | + }else{ |
| 207459 | + pStr->nUsed--; |
| 207460 | + } |
| 207461 | + return; |
| 205883 | 207462 | }else if( isFinal ){ |
| 205884 | 207463 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, |
| 205885 | 207464 | pStr->bStatic ? SQLITE_TRANSIENT : |
| 205886 | 207465 | sqlite3RCStrUnref); |
| 205887 | 207466 | pStr->bStatic = 1; |
| | @@ -205905,33 +207484,51 @@ |
| 205905 | 207484 | |
| 205906 | 207485 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 205907 | 207486 | /**************************************************************************** |
| 205908 | 207487 | ** The json_each virtual table |
| 205909 | 207488 | ****************************************************************************/ |
| 207489 | +typedef struct JsonParent JsonParent; |
| 207490 | +struct JsonParent { |
| 207491 | + u32 iHead; /* Start of object or array */ |
| 207492 | + u32 iValue; /* Start of the value */ |
| 207493 | + u32 iEnd; /* First byte past the end */ |
| 207494 | + u32 nPath; /* Length of path */ |
| 207495 | + i64 iKey; /* Key for JSONB_ARRAY */ |
| 207496 | +}; |
| 207497 | + |
| 205910 | 207498 | typedef struct JsonEachCursor JsonEachCursor; |
| 205911 | 207499 | struct JsonEachCursor { |
| 205912 | 207500 | sqlite3_vtab_cursor base; /* Base class - must be first */ |
| 205913 | 207501 | u32 iRowid; /* The rowid */ |
| 205914 | | - u32 iBegin; /* The first node of the scan */ |
| 205915 | | - u32 i; /* Index in sParse.aNode[] of current row */ |
| 207502 | + u32 i; /* Index in sParse.aBlob[] of current row */ |
| 205916 | 207503 | u32 iEnd; /* EOF when i equals or exceeds this value */ |
| 205917 | | - u8 eType; /* Type of top-level element */ |
| 207504 | + u32 nRoot; /* Size of the root path in bytes */ |
| 207505 | + u8 eType; /* Type of the container for element i */ |
| 205918 | 207506 | u8 bRecursive; /* True for json_tree(). False for json_each() */ |
| 205919 | | - char *zJson; /* Input JSON */ |
| 205920 | | - char *zRoot; /* Path by which to filter zJson */ |
| 207507 | + u32 nParent; /* Current nesting depth */ |
| 207508 | + u32 nParentAlloc; /* Space allocated for aParent[] */ |
| 207509 | + JsonParent *aParent; /* Parent elements of i */ |
| 207510 | + sqlite3 *db; /* Database connection */ |
| 207511 | + JsonString path; /* Current path */ |
| 205921 | 207512 | JsonParse sParse; /* Parse of the input JSON */ |
| 205922 | 207513 | }; |
| 207514 | +typedef struct JsonEachConnection JsonEachConnection; |
| 207515 | +struct JsonEachConnection { |
| 207516 | + sqlite3_vtab base; /* Base class - must be first */ |
| 207517 | + sqlite3 *db; /* Database connection */ |
| 207518 | +}; |
| 207519 | + |
| 205923 | 207520 | |
| 205924 | 207521 | /* Constructor for the json_each virtual table */ |
| 205925 | 207522 | static int jsonEachConnect( |
| 205926 | 207523 | sqlite3 *db, |
| 205927 | 207524 | void *pAux, |
| 205928 | 207525 | int argc, const char *const*argv, |
| 205929 | 207526 | sqlite3_vtab **ppVtab, |
| 205930 | 207527 | char **pzErr |
| 205931 | 207528 | ){ |
| 205932 | | - sqlite3_vtab *pNew; |
| 207529 | + JsonEachConnection *pNew; |
| 205933 | 207530 | int rc; |
| 205934 | 207531 | |
| 205935 | 207532 | /* Column numbers */ |
| 205936 | 207533 | #define JEACH_KEY 0 |
| 205937 | 207534 | #define JEACH_VALUE 1 |
| | @@ -205953,14 +207550,15 @@ |
| 205953 | 207550 | UNUSED_PARAMETER(pAux); |
| 205954 | 207551 | rc = sqlite3_declare_vtab(db, |
| 205955 | 207552 | "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path," |
| 205956 | 207553 | "json HIDDEN,root HIDDEN)"); |
| 205957 | 207554 | if( rc==SQLITE_OK ){ |
| 205958 | | - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); |
| 207555 | + pNew = (JsonEachConnection*)(*ppVtab = sqlite3_malloc( sizeof(*pNew) )); |
| 205959 | 207556 | if( pNew==0 ) return SQLITE_NOMEM; |
| 205960 | 207557 | memset(pNew, 0, sizeof(*pNew)); |
| 205961 | 207558 | sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); |
| 207559 | + pNew->db = db; |
| 205962 | 207560 | } |
| 205963 | 207561 | return rc; |
| 205964 | 207562 | } |
| 205965 | 207563 | |
| 205966 | 207564 | /* destructor for json_each virtual table */ |
| | @@ -205969,16 +207567,19 @@ |
| 205969 | 207567 | return SQLITE_OK; |
| 205970 | 207568 | } |
| 205971 | 207569 | |
| 205972 | 207570 | /* constructor for a JsonEachCursor object for json_each(). */ |
| 205973 | 207571 | static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ |
| 207572 | + JsonEachConnection *pVtab = (JsonEachConnection*)p; |
| 205974 | 207573 | JsonEachCursor *pCur; |
| 205975 | 207574 | |
| 205976 | 207575 | UNUSED_PARAMETER(p); |
| 205977 | 207576 | pCur = sqlite3_malloc( sizeof(*pCur) ); |
| 205978 | 207577 | if( pCur==0 ) return SQLITE_NOMEM; |
| 205979 | 207578 | memset(pCur, 0, sizeof(*pCur)); |
| 207579 | + pCur->db = pVtab->db; |
| 207580 | + jsonStringZero(&pCur->path); |
| 205980 | 207581 | *ppCursor = &pCur->base; |
| 205981 | 207582 | return SQLITE_OK; |
| 205982 | 207583 | } |
| 205983 | 207584 | |
| 205984 | 207585 | /* constructor for a JsonEachCursor object for json_tree(). */ |
| | @@ -205992,24 +207593,27 @@ |
| 205992 | 207593 | } |
| 205993 | 207594 | |
| 205994 | 207595 | /* Reset a JsonEachCursor back to its original state. Free any memory |
| 205995 | 207596 | ** held. */ |
| 205996 | 207597 | static void jsonEachCursorReset(JsonEachCursor *p){ |
| 205997 | | - sqlite3_free(p->zRoot); |
| 205998 | 207598 | jsonParseReset(&p->sParse); |
| 207599 | + jsonStringReset(&p->path); |
| 207600 | + sqlite3DbFree(p->db, p->aParent); |
| 205999 | 207601 | p->iRowid = 0; |
| 206000 | 207602 | p->i = 0; |
| 207603 | + p->aParent = 0; |
| 207604 | + p->nParent = 0; |
| 207605 | + p->nParentAlloc = 0; |
| 206001 | 207606 | p->iEnd = 0; |
| 206002 | 207607 | p->eType = 0; |
| 206003 | | - p->zJson = 0; |
| 206004 | | - p->zRoot = 0; |
| 206005 | 207608 | } |
| 206006 | 207609 | |
| 206007 | 207610 | /* Destructor for a jsonEachCursor object */ |
| 206008 | 207611 | static int jsonEachClose(sqlite3_vtab_cursor *cur){ |
| 206009 | 207612 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 206010 | 207613 | jsonEachCursorReset(p); |
| 207614 | + |
| 206011 | 207615 | sqlite3_free(cur); |
| 206012 | 207616 | return SQLITE_OK; |
| 206013 | 207617 | } |
| 206014 | 207618 | |
| 206015 | 207619 | /* Return TRUE if the jsonEachCursor object has been advanced off the end |
| | @@ -206016,205 +207620,235 @@ |
| 206016 | 207620 | ** of the JSON object */ |
| 206017 | 207621 | static int jsonEachEof(sqlite3_vtab_cursor *cur){ |
| 206018 | 207622 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 206019 | 207623 | return p->i >= p->iEnd; |
| 206020 | 207624 | } |
| 207625 | + |
| 207626 | +/* |
| 207627 | +** If the cursor is currently pointing at the label of a object entry, |
| 207628 | +** then return the index of the value. For all other cases, return the |
| 207629 | +** current pointer position, which is the value. |
| 207630 | +*/ |
| 207631 | +static int jsonSkipLabel(JsonEachCursor *p){ |
| 207632 | + if( p->eType==JSONB_OBJECT ){ |
| 207633 | + u32 sz = 0; |
| 207634 | + u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz); |
| 207635 | + return p->i + n + sz; |
| 207636 | + }else{ |
| 207637 | + return p->i; |
| 207638 | + } |
| 207639 | +} |
| 207640 | + |
| 207641 | +/* |
| 207642 | +** Append the path name for the current element. |
| 207643 | +*/ |
| 207644 | +static void jsonAppendPathName(JsonEachCursor *p){ |
| 207645 | + assert( p->nParent>0 ); |
| 207646 | + assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT ); |
| 207647 | + if( p->eType==JSONB_ARRAY ){ |
| 207648 | + jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey); |
| 207649 | + }else{ |
| 207650 | + u32 n, sz = 0, k, i; |
| 207651 | + const char *z; |
| 207652 | + int needQuote = 0; |
| 207653 | + n = jsonbPayloadSize(&p->sParse, p->i, &sz); |
| 207654 | + k = p->i + n; |
| 207655 | + z = (const char*)&p->sParse.aBlob[k]; |
| 207656 | + if( sz==0 || !sqlite3Isalpha(z[0]) ){ |
| 207657 | + needQuote = 1; |
| 207658 | + }else{ |
| 207659 | + for(i=0; i<sz; i++){ |
| 207660 | + if( !sqlite3Isalnum(z[i]) ){ |
| 207661 | + needQuote = 1; |
| 207662 | + break; |
| 207663 | + } |
| 207664 | + } |
| 207665 | + } |
| 207666 | + if( needQuote ){ |
| 207667 | + jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z); |
| 207668 | + }else{ |
| 207669 | + jsonPrintf(sz+2,&p->path,".%.*s", sz, z); |
| 207670 | + } |
| 207671 | + } |
| 207672 | +} |
| 206021 | 207673 | |
| 206022 | 207674 | /* Advance the cursor to the next element for json_tree() */ |
| 206023 | 207675 | static int jsonEachNext(sqlite3_vtab_cursor *cur){ |
| 206024 | 207676 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 207677 | + int rc = SQLITE_OK; |
| 206025 | 207678 | if( p->bRecursive ){ |
| 206026 | | - if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; |
| 206027 | | - p->i++; |
| 206028 | | - p->iRowid++; |
| 206029 | | - if( p->i<p->iEnd ){ |
| 206030 | | - u32 iUp = p->sParse.aUp[p->i]; |
| 206031 | | - JsonNode *pUp = &p->sParse.aNode[iUp]; |
| 206032 | | - p->eType = pUp->eType; |
| 206033 | | - if( pUp->eType==JSON_ARRAY ){ |
| 206034 | | - assert( pUp->eU==0 || pUp->eU==3 ); |
| 206035 | | - testcase( pUp->eU==3 ); |
| 206036 | | - VVA( pUp->eU = 3 ); |
| 206037 | | - if( iUp==p->i-1 ){ |
| 206038 | | - pUp->u.iKey = 0; |
| 206039 | | - }else{ |
| 206040 | | - pUp->u.iKey++; |
| 206041 | | - } |
| 206042 | | - } |
| 206043 | | - } |
| 206044 | | - }else{ |
| 206045 | | - switch( p->eType ){ |
| 206046 | | - case JSON_ARRAY: { |
| 206047 | | - p->i += jsonNodeSize(&p->sParse.aNode[p->i]); |
| 206048 | | - p->iRowid++; |
| 206049 | | - break; |
| 206050 | | - } |
| 206051 | | - case JSON_OBJECT: { |
| 206052 | | - p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); |
| 206053 | | - p->iRowid++; |
| 206054 | | - break; |
| 206055 | | - } |
| 206056 | | - default: { |
| 206057 | | - p->i = p->iEnd; |
| 206058 | | - break; |
| 206059 | | - } |
| 206060 | | - } |
| 206061 | | - } |
| 206062 | | - return SQLITE_OK; |
| 206063 | | -} |
| 206064 | | - |
| 206065 | | -/* Append an object label to the JSON Path being constructed |
| 206066 | | -** in pStr. |
| 206067 | | -*/ |
| 206068 | | -static void jsonAppendObjectPathElement( |
| 206069 | | - JsonString *pStr, |
| 206070 | | - JsonNode *pNode |
| 206071 | | -){ |
| 206072 | | - int jj, nn; |
| 206073 | | - const char *z; |
| 206074 | | - assert( pNode->eType==JSON_STRING ); |
| 206075 | | - assert( pNode->jnFlags & JNODE_LABEL ); |
| 206076 | | - assert( pNode->eU==1 ); |
| 206077 | | - z = pNode->u.zJContent; |
| 206078 | | - nn = pNode->n; |
| 206079 | | - if( (pNode->jnFlags & JNODE_RAW)==0 ){ |
| 206080 | | - assert( nn>=2 ); |
| 206081 | | - assert( z[0]=='"' || z[0]=='\'' ); |
| 206082 | | - assert( z[nn-1]=='"' || z[0]=='\'' ); |
| 206083 | | - if( nn>2 && sqlite3Isalpha(z[1]) ){ |
| 206084 | | - for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){} |
| 206085 | | - if( jj==nn-1 ){ |
| 206086 | | - z++; |
| 206087 | | - nn -= 2; |
| 206088 | | - } |
| 206089 | | - } |
| 206090 | | - } |
| 206091 | | - jsonPrintf(nn+2, pStr, ".%.*s", nn, z); |
| 206092 | | -} |
| 206093 | | - |
| 206094 | | -/* Append the name of the path for element i to pStr |
| 206095 | | -*/ |
| 206096 | | -static void jsonEachComputePath( |
| 206097 | | - JsonEachCursor *p, /* The cursor */ |
| 206098 | | - JsonString *pStr, /* Write the path here */ |
| 206099 | | - u32 i /* Path to this element */ |
| 206100 | | -){ |
| 206101 | | - JsonNode *pNode, *pUp; |
| 206102 | | - u32 iUp; |
| 206103 | | - if( i==0 ){ |
| 206104 | | - jsonAppendChar(pStr, '$'); |
| 206105 | | - return; |
| 206106 | | - } |
| 206107 | | - iUp = p->sParse.aUp[i]; |
| 206108 | | - jsonEachComputePath(p, pStr, iUp); |
| 206109 | | - pNode = &p->sParse.aNode[i]; |
| 206110 | | - pUp = &p->sParse.aNode[iUp]; |
| 206111 | | - if( pUp->eType==JSON_ARRAY ){ |
| 206112 | | - assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) ); |
| 206113 | | - testcase( pUp->eU==0 ); |
| 206114 | | - jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); |
| 206115 | | - }else{ |
| 206116 | | - assert( pUp->eType==JSON_OBJECT ); |
| 206117 | | - if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; |
| 206118 | | - jsonAppendObjectPathElement(pStr, pNode); |
| 206119 | | - } |
| 207679 | + u8 x; |
| 207680 | + u8 levelChange = 0; |
| 207681 | + u32 n, sz = 0; |
| 207682 | + u32 i = jsonSkipLabel(p); |
| 207683 | + x = p->sParse.aBlob[i] & 0x0f; |
| 207684 | + n = jsonbPayloadSize(&p->sParse, i, &sz); |
| 207685 | + if( x==JSONB_OBJECT || x==JSONB_ARRAY ){ |
| 207686 | + JsonParent *pParent; |
| 207687 | + if( p->nParent>=p->nParentAlloc ){ |
| 207688 | + JsonParent *pNew; |
| 207689 | + u64 nNew; |
| 207690 | + nNew = p->nParentAlloc*2 + 3; |
| 207691 | + pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew); |
| 207692 | + if( pNew==0 ) return SQLITE_NOMEM; |
| 207693 | + p->nParentAlloc = (u32)nNew; |
| 207694 | + p->aParent = pNew; |
| 207695 | + } |
| 207696 | + levelChange = 1; |
| 207697 | + pParent = &p->aParent[p->nParent]; |
| 207698 | + pParent->iHead = p->i; |
| 207699 | + pParent->iValue = i; |
| 207700 | + pParent->iEnd = i + n + sz; |
| 207701 | + pParent->iKey = -1; |
| 207702 | + pParent->nPath = (u32)p->path.nUsed; |
| 207703 | + if( p->eType && p->nParent ){ |
| 207704 | + jsonAppendPathName(p); |
| 207705 | + if( p->path.eErr ) rc = SQLITE_NOMEM; |
| 207706 | + } |
| 207707 | + p->nParent++; |
| 207708 | + p->i = i + n; |
| 207709 | + }else{ |
| 207710 | + p->i = i + n + sz; |
| 207711 | + } |
| 207712 | + while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){ |
| 207713 | + p->nParent--; |
| 207714 | + p->path.nUsed = p->aParent[p->nParent].nPath; |
| 207715 | + levelChange = 1; |
| 207716 | + } |
| 207717 | + if( levelChange ){ |
| 207718 | + if( p->nParent>0 ){ |
| 207719 | + JsonParent *pParent = &p->aParent[p->nParent-1]; |
| 207720 | + u32 iVal = pParent->iValue; |
| 207721 | + p->eType = p->sParse.aBlob[iVal] & 0x0f; |
| 207722 | + }else{ |
| 207723 | + p->eType = 0; |
| 207724 | + } |
| 207725 | + } |
| 207726 | + }else{ |
| 207727 | + u32 n, sz = 0; |
| 207728 | + u32 i = jsonSkipLabel(p); |
| 207729 | + n = jsonbPayloadSize(&p->sParse, i, &sz); |
| 207730 | + p->i = i + n + sz; |
| 207731 | + } |
| 207732 | + if( p->eType==JSONB_ARRAY && p->nParent ){ |
| 207733 | + p->aParent[p->nParent-1].iKey++; |
| 207734 | + } |
| 207735 | + p->iRowid++; |
| 207736 | + return rc; |
| 207737 | +} |
| 207738 | + |
| 207739 | +/* Length of the path for rowid==0 in bRecursive mode. |
| 207740 | +*/ |
| 207741 | +static int jsonEachPathLength(JsonEachCursor *p){ |
| 207742 | + u32 n = p->path.nUsed; |
| 207743 | + char *z = p->path.zBuf; |
| 207744 | + if( p->iRowid==0 && p->bRecursive && n>=2 ){ |
| 207745 | + while( n>1 ){ |
| 207746 | + n--; |
| 207747 | + if( z[n]=='[' || z[n]=='.' ){ |
| 207748 | + u32 x, sz = 0; |
| 207749 | + char cSaved = z[n]; |
| 207750 | + z[n] = 0; |
| 207751 | + assert( p->sParse.eEdit==0 ); |
| 207752 | + x = jsonLookupStep(&p->sParse, 0, z+1, 0); |
| 207753 | + z[n] = cSaved; |
| 207754 | + if( JSON_LOOKUP_ISERROR(x) ) continue; |
| 207755 | + if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break; |
| 207756 | + } |
| 207757 | + } |
| 207758 | + } |
| 207759 | + return n; |
| 206120 | 207760 | } |
| 206121 | 207761 | |
| 206122 | 207762 | /* Return the value of a column */ |
| 206123 | 207763 | static int jsonEachColumn( |
| 206124 | 207764 | sqlite3_vtab_cursor *cur, /* The cursor */ |
| 206125 | 207765 | sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ |
| 206126 | | - int i /* Which column to return */ |
| 207766 | + int iColumn /* Which column to return */ |
| 206127 | 207767 | ){ |
| 206128 | 207768 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 206129 | | - JsonNode *pThis = &p->sParse.aNode[p->i]; |
| 206130 | | - switch( i ){ |
| 207769 | + switch( iColumn ){ |
| 206131 | 207770 | case JEACH_KEY: { |
| 206132 | | - if( p->i==0 ) break; |
| 206133 | | - if( p->eType==JSON_OBJECT ){ |
| 206134 | | - jsonReturn(&p->sParse, pThis, ctx, 0); |
| 206135 | | - }else if( p->eType==JSON_ARRAY ){ |
| 206136 | | - u32 iKey; |
| 206137 | | - if( p->bRecursive ){ |
| 206138 | | - if( p->iRowid==0 ) break; |
| 206139 | | - assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 ); |
| 206140 | | - iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; |
| 207771 | + if( p->nParent==0 ){ |
| 207772 | + u32 n, j; |
| 207773 | + if( p->nRoot==1 ) break; |
| 207774 | + j = jsonEachPathLength(p); |
| 207775 | + n = p->nRoot - j; |
| 207776 | + if( n==0 ){ |
| 207777 | + break; |
| 207778 | + }else if( p->path.zBuf[j]=='[' ){ |
| 207779 | + i64 x; |
| 207780 | + sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8); |
| 207781 | + sqlite3_result_int64(ctx, x); |
| 207782 | + }else if( p->path.zBuf[j+1]=='"' ){ |
| 207783 | + sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT); |
| 206141 | 207784 | }else{ |
| 206142 | | - iKey = p->iRowid; |
| 207785 | + sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT); |
| 206143 | 207786 | } |
| 206144 | | - sqlite3_result_int64(ctx, (sqlite3_int64)iKey); |
| 207787 | + break; |
| 207788 | + } |
| 207789 | + if( p->eType==JSONB_OBJECT ){ |
| 207790 | + jsonReturnFromBlob(&p->sParse, p->i, ctx, 1); |
| 207791 | + }else{ |
| 207792 | + assert( p->eType==JSONB_ARRAY ); |
| 207793 | + sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey); |
| 206145 | 207794 | } |
| 206146 | 207795 | break; |
| 206147 | 207796 | } |
| 206148 | 207797 | case JEACH_VALUE: { |
| 206149 | | - if( pThis->jnFlags & JNODE_LABEL ) pThis++; |
| 206150 | | - jsonReturn(&p->sParse, pThis, ctx, 0); |
| 207798 | + u32 i = jsonSkipLabel(p); |
| 207799 | + jsonReturnFromBlob(&p->sParse, i, ctx, 1); |
| 206151 | 207800 | break; |
| 206152 | 207801 | } |
| 206153 | 207802 | case JEACH_TYPE: { |
| 206154 | | - if( pThis->jnFlags & JNODE_LABEL ) pThis++; |
| 206155 | | - sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); |
| 207803 | + u32 i = jsonSkipLabel(p); |
| 207804 | + u8 eType = p->sParse.aBlob[i] & 0x0f; |
| 207805 | + sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC); |
| 206156 | 207806 | break; |
| 206157 | 207807 | } |
| 206158 | 207808 | case JEACH_ATOM: { |
| 206159 | | - if( pThis->jnFlags & JNODE_LABEL ) pThis++; |
| 206160 | | - if( pThis->eType>=JSON_ARRAY ) break; |
| 206161 | | - jsonReturn(&p->sParse, pThis, ctx, 0); |
| 207809 | + u32 i = jsonSkipLabel(p); |
| 207810 | + if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){ |
| 207811 | + jsonReturnFromBlob(&p->sParse, i, ctx, 1); |
| 207812 | + } |
| 206162 | 207813 | break; |
| 206163 | 207814 | } |
| 206164 | 207815 | case JEACH_ID: { |
| 206165 | | - sqlite3_result_int64(ctx, |
| 206166 | | - (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); |
| 207816 | + sqlite3_result_int64(ctx, (sqlite3_int64)p->i); |
| 206167 | 207817 | break; |
| 206168 | 207818 | } |
| 206169 | 207819 | case JEACH_PARENT: { |
| 206170 | | - if( p->i>p->iBegin && p->bRecursive ){ |
| 206171 | | - sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); |
| 207820 | + if( p->nParent>0 && p->bRecursive ){ |
| 207821 | + sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead); |
| 206172 | 207822 | } |
| 206173 | 207823 | break; |
| 206174 | 207824 | } |
| 206175 | 207825 | case JEACH_FULLKEY: { |
| 206176 | | - JsonString x; |
| 206177 | | - jsonInit(&x, ctx); |
| 206178 | | - if( p->bRecursive ){ |
| 206179 | | - jsonEachComputePath(p, &x, p->i); |
| 206180 | | - }else{ |
| 206181 | | - if( p->zRoot ){ |
| 206182 | | - jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot)); |
| 206183 | | - }else{ |
| 206184 | | - jsonAppendChar(&x, '$'); |
| 206185 | | - } |
| 206186 | | - if( p->eType==JSON_ARRAY ){ |
| 206187 | | - jsonPrintf(30, &x, "[%d]", p->iRowid); |
| 206188 | | - }else if( p->eType==JSON_OBJECT ){ |
| 206189 | | - jsonAppendObjectPathElement(&x, pThis); |
| 206190 | | - } |
| 206191 | | - } |
| 206192 | | - jsonResult(&x); |
| 207826 | + u64 nBase = p->path.nUsed; |
| 207827 | + if( p->nParent ) jsonAppendPathName(p); |
| 207828 | + sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed, |
| 207829 | + SQLITE_TRANSIENT, SQLITE_UTF8); |
| 207830 | + p->path.nUsed = nBase; |
| 206193 | 207831 | break; |
| 206194 | 207832 | } |
| 206195 | 207833 | case JEACH_PATH: { |
| 206196 | | - if( p->bRecursive ){ |
| 206197 | | - JsonString x; |
| 206198 | | - jsonInit(&x, ctx); |
| 206199 | | - jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); |
| 206200 | | - jsonResult(&x); |
| 206201 | | - break; |
| 206202 | | - } |
| 206203 | | - /* For json_each() path and root are the same so fall through |
| 206204 | | - ** into the root case */ |
| 206205 | | - /* no break */ deliberate_fall_through |
| 207834 | + u32 n = jsonEachPathLength(p); |
| 207835 | + sqlite3_result_text64(ctx, p->path.zBuf, n, |
| 207836 | + SQLITE_TRANSIENT, SQLITE_UTF8); |
| 207837 | + break; |
| 206206 | 207838 | } |
| 206207 | 207839 | default: { |
| 206208 | | - const char *zRoot = p->zRoot; |
| 206209 | | - if( zRoot==0 ) zRoot = "$"; |
| 206210 | | - sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); |
| 207840 | + sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC); |
| 206211 | 207841 | break; |
| 206212 | 207842 | } |
| 206213 | 207843 | case JEACH_JSON: { |
| 206214 | | - assert( i==JEACH_JSON ); |
| 206215 | | - sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); |
| 207844 | + if( p->sParse.zJson==0 ){ |
| 207845 | + sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob, |
| 207846 | + SQLITE_STATIC); |
| 207847 | + }else{ |
| 207848 | + sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); |
| 207849 | + } |
| 206216 | 207850 | break; |
| 206217 | 207851 | } |
| 206218 | 207852 | } |
| 206219 | 207853 | return SQLITE_OK; |
| 206220 | 207854 | } |
| | @@ -206301,90 +207935,104 @@ |
| 206301 | 207935 | sqlite3_vtab_cursor *cur, |
| 206302 | 207936 | int idxNum, const char *idxStr, |
| 206303 | 207937 | int argc, sqlite3_value **argv |
| 206304 | 207938 | ){ |
| 206305 | 207939 | JsonEachCursor *p = (JsonEachCursor*)cur; |
| 206306 | | - const char *z; |
| 206307 | 207940 | const char *zRoot = 0; |
| 206308 | | - sqlite3_int64 n; |
| 207941 | + u32 i, n, sz; |
| 206309 | 207942 | |
| 206310 | 207943 | UNUSED_PARAMETER(idxStr); |
| 206311 | 207944 | UNUSED_PARAMETER(argc); |
| 206312 | 207945 | jsonEachCursorReset(p); |
| 206313 | 207946 | if( idxNum==0 ) return SQLITE_OK; |
| 206314 | | - z = (const char*)sqlite3_value_text(argv[0]); |
| 206315 | | - if( z==0 ) return SQLITE_OK; |
| 206316 | 207947 | memset(&p->sParse, 0, sizeof(p->sParse)); |
| 206317 | 207948 | p->sParse.nJPRef = 1; |
| 206318 | | - if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){ |
| 206319 | | - p->sParse.zJson = sqlite3RCStrRef((char*)z); |
| 206320 | | - }else{ |
| 206321 | | - n = sqlite3_value_bytes(argv[0]); |
| 206322 | | - p->sParse.zJson = sqlite3RCStrNew( n+1 ); |
| 206323 | | - if( p->sParse.zJson==0 ) return SQLITE_NOMEM; |
| 206324 | | - memcpy(p->sParse.zJson, z, (size_t)n+1); |
| 206325 | | - } |
| 206326 | | - p->sParse.bJsonIsRCStr = 1; |
| 206327 | | - p->zJson = p->sParse.zJson; |
| 206328 | | - if( jsonParse(&p->sParse, 0) ){ |
| 206329 | | - int rc = SQLITE_NOMEM; |
| 206330 | | - if( p->sParse.oom==0 ){ |
| 206331 | | - sqlite3_free(cur->pVtab->zErrMsg); |
| 206332 | | - cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); |
| 206333 | | - if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; |
| 206334 | | - } |
| 206335 | | - jsonEachCursorReset(p); |
| 206336 | | - return rc; |
| 206337 | | - }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ |
| 206338 | | - jsonEachCursorReset(p); |
| 206339 | | - return SQLITE_NOMEM; |
| 206340 | | - }else{ |
| 206341 | | - JsonNode *pNode = 0; |
| 206342 | | - if( idxNum==3 ){ |
| 206343 | | - const char *zErr = 0; |
| 206344 | | - zRoot = (const char*)sqlite3_value_text(argv[1]); |
| 206345 | | - if( zRoot==0 ) return SQLITE_OK; |
| 206346 | | - n = sqlite3_value_bytes(argv[1]); |
| 206347 | | - p->zRoot = sqlite3_malloc64( n+1 ); |
| 206348 | | - if( p->zRoot==0 ) return SQLITE_NOMEM; |
| 206349 | | - memcpy(p->zRoot, zRoot, (size_t)n+1); |
| 206350 | | - if( zRoot[0]!='$' ){ |
| 206351 | | - zErr = zRoot; |
| 206352 | | - }else{ |
| 206353 | | - pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); |
| 206354 | | - } |
| 206355 | | - if( zErr ){ |
| 206356 | | - sqlite3_free(cur->pVtab->zErrMsg); |
| 206357 | | - cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); |
| 207949 | + if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ |
| 207950 | + if( jsonFuncArgMightBeBinary(argv[0]) ){ |
| 207951 | + p->sParse.nBlob = sqlite3_value_bytes(argv[0]); |
| 207952 | + p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 207953 | + }else{ |
| 207954 | + goto json_each_malformed_input; |
| 207955 | + } |
| 207956 | + }else{ |
| 207957 | + p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); |
| 207958 | + p->sParse.nJson = sqlite3_value_bytes(argv[0]); |
| 207959 | + if( p->sParse.zJson==0 ){ |
| 207960 | + p->i = p->iEnd = 0; |
| 207961 | + return SQLITE_OK; |
| 207962 | + } |
| 207963 | + if( jsonConvertTextToBlob(&p->sParse, 0) ){ |
| 207964 | + if( p->sParse.oom ){ |
| 207965 | + return SQLITE_NOMEM; |
| 207966 | + } |
| 207967 | + goto json_each_malformed_input; |
| 207968 | + } |
| 207969 | + } |
| 207970 | + if( idxNum==3 ){ |
| 207971 | + zRoot = (const char*)sqlite3_value_text(argv[1]); |
| 207972 | + if( zRoot==0 ) return SQLITE_OK; |
| 207973 | + if( zRoot[0]!='$' ){ |
| 207974 | + sqlite3_free(cur->pVtab->zErrMsg); |
| 207975 | + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); |
| 207976 | + jsonEachCursorReset(p); |
| 207977 | + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; |
| 207978 | + } |
| 207979 | + p->nRoot = sqlite3Strlen30(zRoot); |
| 207980 | + if( zRoot[1]==0 ){ |
| 207981 | + i = p->i = 0; |
| 207982 | + p->eType = 0; |
| 207983 | + }else{ |
| 207984 | + i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0); |
| 207985 | + if( JSON_LOOKUP_ISERROR(i) ){ |
| 207986 | + if( i==JSON_LOOKUP_NOTFOUND ){ |
| 207987 | + p->i = 0; |
| 207988 | + p->eType = 0; |
| 207989 | + p->iEnd = 0; |
| 207990 | + return SQLITE_OK; |
| 207991 | + } |
| 207992 | + sqlite3_free(cur->pVtab->zErrMsg); |
| 207993 | + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); |
| 206358 | 207994 | jsonEachCursorReset(p); |
| 206359 | 207995 | return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; |
| 206360 | | - }else if( pNode==0 ){ |
| 206361 | | - return SQLITE_OK; |
| 206362 | | - } |
| 206363 | | - }else{ |
| 206364 | | - pNode = p->sParse.aNode; |
| 206365 | | - } |
| 206366 | | - p->iBegin = p->i = (int)(pNode - p->sParse.aNode); |
| 206367 | | - p->eType = pNode->eType; |
| 206368 | | - if( p->eType>=JSON_ARRAY ){ |
| 206369 | | - assert( pNode->eU==0 ); |
| 206370 | | - VVA( pNode->eU = 3 ); |
| 206371 | | - pNode->u.iKey = 0; |
| 206372 | | - p->iEnd = p->i + pNode->n + 1; |
| 206373 | | - if( p->bRecursive ){ |
| 206374 | | - p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType; |
| 206375 | | - if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ |
| 206376 | | - p->i--; |
| 206377 | | - } |
| 206378 | | - }else{ |
| 206379 | | - p->i++; |
| 206380 | | - } |
| 206381 | | - }else{ |
| 206382 | | - p->iEnd = p->i+1; |
| 206383 | | - } |
| 206384 | | - } |
| 206385 | | - return SQLITE_OK; |
| 207996 | + } |
| 207997 | + if( p->sParse.iLabel ){ |
| 207998 | + p->i = p->sParse.iLabel; |
| 207999 | + p->eType = JSONB_OBJECT; |
| 208000 | + }else{ |
| 208001 | + p->i = i; |
| 208002 | + p->eType = JSONB_ARRAY; |
| 208003 | + } |
| 208004 | + } |
| 208005 | + jsonAppendRaw(&p->path, zRoot, p->nRoot); |
| 208006 | + }else{ |
| 208007 | + i = p->i = 0; |
| 208008 | + p->eType = 0; |
| 208009 | + p->nRoot = 1; |
| 208010 | + jsonAppendRaw(&p->path, "$", 1); |
| 208011 | + } |
| 208012 | + p->nParent = 0; |
| 208013 | + n = jsonbPayloadSize(&p->sParse, i, &sz); |
| 208014 | + p->iEnd = i+n+sz; |
| 208015 | + if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){ |
| 208016 | + p->i = i + n; |
| 208017 | + p->eType = p->sParse.aBlob[i] & 0x0f; |
| 208018 | + p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent)); |
| 208019 | + if( p->aParent==0 ) return SQLITE_NOMEM; |
| 208020 | + p->nParent = 1; |
| 208021 | + p->nParentAlloc = 1; |
| 208022 | + p->aParent[0].iKey = 0; |
| 208023 | + p->aParent[0].iEnd = p->iEnd; |
| 208024 | + p->aParent[0].iHead = p->i; |
| 208025 | + p->aParent[0].iValue = i; |
| 208026 | + } |
| 208027 | + return SQLITE_OK; |
| 208028 | + |
| 208029 | +json_each_malformed_input: |
| 208030 | + sqlite3_free(cur->pVtab->zErrMsg); |
| 208031 | + cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); |
| 208032 | + jsonEachCursorReset(p); |
| 208033 | + return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; |
| 206386 | 208034 | } |
| 206387 | 208035 | |
| 206388 | 208036 | /* The methods of the json_each virtual table */ |
| 206389 | 208037 | static sqlite3_module jsonEachModule = { |
| 206390 | 208038 | 0, /* iVersion */ |
| | @@ -206449,44 +208097,58 @@ |
| 206449 | 208097 | ** Register JSON functions. |
| 206450 | 208098 | */ |
| 206451 | 208099 | SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ |
| 206452 | 208100 | #ifndef SQLITE_OMIT_JSON |
| 206453 | 208101 | static FuncDef aJsonFunc[] = { |
| 206454 | | - /* calls sqlite3_result_subtype() */ |
| 206455 | | - /* | */ |
| 206456 | | - /* Uses cache ______ | __ calls sqlite3_value_subtype() */ |
| 206457 | | - /* | | | */ |
| 206458 | | - /* Num args _________ | | | ___ Flags */ |
| 206459 | | - /* | | | | | */ |
| 206460 | | - /* | | | | | */ |
| 206461 | | - JFUNCTION(json, 1, 1, 1, 0, 0, jsonRemoveFunc), |
| 206462 | | - JFUNCTION(json_array, -1, 0, 1, 1, 0, jsonArrayFunc), |
| 206463 | | - JFUNCTION(json_array_length, 1, 1, 0, 0, 0, jsonArrayLengthFunc), |
| 206464 | | - JFUNCTION(json_array_length, 2, 1, 0, 0, 0, jsonArrayLengthFunc), |
| 206465 | | - JFUNCTION(json_error_position,1, 1, 0, 0, 0, jsonErrorFunc), |
| 206466 | | - JFUNCTION(json_extract, -1, 1, 1, 0, 0, jsonExtractFunc), |
| 206467 | | - JFUNCTION(->, 2, 1, 1, 0, JSON_JSON, jsonExtractFunc), |
| 206468 | | - JFUNCTION(->>, 2, 1, 0, 0, JSON_SQL, jsonExtractFunc), |
| 206469 | | - JFUNCTION(json_insert, -1, 1, 1, 1, 0, jsonSetFunc), |
| 206470 | | - JFUNCTION(json_object, -1, 0, 1, 1, 0, jsonObjectFunc), |
| 206471 | | - JFUNCTION(json_patch, 2, 1, 1, 0, 0, jsonPatchFunc), |
| 206472 | | - JFUNCTION(json_quote, 1, 0, 1, 1, 0, jsonQuoteFunc), |
| 206473 | | - JFUNCTION(json_remove, -1, 1, 1, 0, 0, jsonRemoveFunc), |
| 206474 | | - JFUNCTION(json_replace, -1, 1, 1, 1, 0, jsonReplaceFunc), |
| 206475 | | - JFUNCTION(json_set, -1, 1, 1, 1, JSON_ISSET, jsonSetFunc), |
| 206476 | | - JFUNCTION(json_type, 1, 1, 0, 0, 0, jsonTypeFunc), |
| 206477 | | - JFUNCTION(json_type, 2, 1, 0, 0, 0, jsonTypeFunc), |
| 206478 | | - JFUNCTION(json_valid, 1, 1, 0, 0, 0, jsonValidFunc), |
| 206479 | | -#ifdef SQLITE_DEBUG |
| 206480 | | - JFUNCTION(json_parse, 1, 1, 1, 0, 0, jsonParseFunc), |
| 206481 | | - JFUNCTION(json_test1, 1, 1, 0, 1, 0, jsonTest1Func), |
| 208102 | + /* sqlite3_result_subtype() ----, ,--- sqlite3_value_subtype() */ |
| 208103 | + /* | | */ |
| 208104 | + /* Uses cache ------, | | ,---- Returns JSONB */ |
| 208105 | + /* | | | | */ |
| 208106 | + /* Number of arguments ---, | | | | ,--- Flags */ |
| 208107 | + /* | | | | | | */ |
| 208108 | + JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc), |
| 208109 | + JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc), |
| 208110 | + JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc), |
| 208111 | + JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc), |
| 208112 | + JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc), |
| 208113 | + JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc), |
| 208114 | + JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc), |
| 208115 | + JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc), |
| 208116 | + JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc), |
| 208117 | + JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc), |
| 208118 | + JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc), |
| 208119 | + JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc), |
| 208120 | + JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc), |
| 208121 | + JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc), |
| 208122 | + JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc), |
| 208123 | + JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc), |
| 208124 | + JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc), |
| 208125 | + JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc), |
| 208126 | + JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc), |
| 208127 | + JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc), |
| 208128 | + JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc), |
| 208129 | + JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc), |
| 208130 | + JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc), |
| 208131 | + JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc), |
| 208132 | + JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc), |
| 208133 | + JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc), |
| 208134 | + JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc), |
| 208135 | + JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc), |
| 208136 | +#if SQLITE_DEBUG |
| 208137 | + JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc), |
| 206482 | 208138 | #endif |
| 206483 | 208139 | WAGGREGATE(json_group_array, 1, 0, 0, |
| 206484 | 208140 | jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, |
| 206485 | 208141 | SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| |
| 206486 | 208142 | SQLITE_DETERMINISTIC), |
| 208143 | + WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0, |
| 208144 | + jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, |
| 208145 | + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), |
| 206487 | 208146 | WAGGREGATE(json_group_object, 2, 0, 0, |
| 208147 | + jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, |
| 208148 | + SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC), |
| 208149 | + WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0, |
| 206488 | 208150 | jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, |
| 206489 | 208151 | SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8| |
| 206490 | 208152 | SQLITE_DETERMINISTIC) |
| 206491 | 208153 | }; |
| 206492 | 208154 | sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); |
| | @@ -227778,13 +229440,38 @@ |
| 227778 | 229440 | ** significantly more efficient than those alternatives when used with |
| 227779 | 229441 | ** "detail=column" tables. |
| 227780 | 229442 | ** |
| 227781 | 229443 | ** xPhraseNextColumn() |
| 227782 | 229444 | ** See xPhraseFirstColumn above. |
| 229445 | +** |
| 229446 | +** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken) |
| 229447 | +** This is used to access token iToken of phrase iPhrase of the current |
| 229448 | +** query. Before returning, output parameter *ppToken is set to point |
| 229449 | +** to a buffer containing the requested token, and *pnToken to the |
| 229450 | +** size of this buffer in bytes. |
| 229451 | +** |
| 229452 | +** The output text is not a copy of the query text that specified the |
| 229453 | +** token. It is the output of the tokenizer module. For tokendata=1 |
| 229454 | +** tables, this includes any embedded 0x00 and trailing data. |
| 229455 | +** |
| 229456 | +** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken) |
| 229457 | +** This is used to access token iToken of phrase hit iIdx within the |
| 229458 | +** current row. Output variable (*ppToken) is set to point to a buffer |
| 229459 | +** containing the matching document token, and (*pnToken) to the size |
| 229460 | +** of that buffer in bytes. This API is not available if the specified |
| 229461 | +** token matches a prefix query term. In that case both output variables |
| 229462 | +** are always set to 0. |
| 229463 | +** |
| 229464 | +** The output text is not a copy of the document text that was tokenized. |
| 229465 | +** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 229466 | +** includes any embedded 0x00 and trailing data. |
| 229467 | +** |
| 229468 | +** This API can be quite slow if used with an FTS5 table created with the |
| 229469 | +** "detail=none" or "detail=column" option. |
| 227783 | 229470 | */ |
| 227784 | 229471 | struct Fts5ExtensionApi { |
| 227785 | | - int iVersion; /* Currently always set to 2 */ |
| 229472 | + int iVersion; /* Currently always set to 3 */ |
| 227786 | 229473 | |
| 227787 | 229474 | void *(*xUserData)(Fts5Context*); |
| 227788 | 229475 | |
| 227789 | 229476 | int (*xColumnCount)(Fts5Context*); |
| 227790 | 229477 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -227815,10 +229502,17 @@ |
| 227815 | 229502 | int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); |
| 227816 | 229503 | void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); |
| 227817 | 229504 | |
| 227818 | 229505 | int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); |
| 227819 | 229506 | void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); |
| 229507 | + |
| 229508 | + /* Below this point are iVersion>=3 only */ |
| 229509 | + int (*xQueryToken)(Fts5Context*, |
| 229510 | + int iPhrase, int iToken, |
| 229511 | + const char **ppToken, int *pnToken |
| 229512 | + ); |
| 229513 | + int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); |
| 227820 | 229514 | }; |
| 227821 | 229515 | |
| 227822 | 229516 | /* |
| 227823 | 229517 | ** CUSTOM AUXILIARY FUNCTIONS |
| 227824 | 229518 | *************************************************************************/ |
| | @@ -228289,10 +229983,11 @@ |
| 228289 | 229983 | int eContent; /* An FTS5_CONTENT value */ |
| 228290 | 229984 | int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */ |
| 228291 | 229985 | char *zContent; /* content table */ |
| 228292 | 229986 | char *zContentRowid; /* "content_rowid=" option value */ |
| 228293 | 229987 | int bColumnsize; /* "columnsize=" option value (dflt==1) */ |
| 229988 | + int bTokendata; /* "tokendata=" option value (dflt==0) */ |
| 228294 | 229989 | int eDetail; /* FTS5_DETAIL_XXX value */ |
| 228295 | 229990 | char *zContentExprlist; |
| 228296 | 229991 | Fts5Tokenizer *pTok; |
| 228297 | 229992 | fts5_tokenizer *pTokApi; |
| 228298 | 229993 | int bLock; /* True when table is preparing statement */ |
| | @@ -228477,21 +230172,23 @@ |
| 228477 | 230172 | #define sqlite3Fts5IterEof(x) ((x)->bEof) |
| 228478 | 230173 | |
| 228479 | 230174 | /* |
| 228480 | 230175 | ** Values used as part of the flags argument passed to IndexQuery(). |
| 228481 | 230176 | */ |
| 228482 | | -#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ |
| 228483 | | -#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ |
| 228484 | | -#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ |
| 228485 | | -#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ |
| 230177 | +#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ |
| 230178 | +#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ |
| 230179 | +#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */ |
| 230180 | +#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */ |
| 228486 | 230181 | |
| 228487 | 230182 | /* The following are used internally by the fts5_index.c module. They are |
| 228488 | 230183 | ** defined here only to make it easier to avoid clashes with the flags |
| 228489 | 230184 | ** above. */ |
| 228490 | | -#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 |
| 228491 | | -#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 |
| 228492 | | -#define FTS5INDEX_QUERY_SKIPHASH 0x0040 |
| 230185 | +#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010 |
| 230186 | +#define FTS5INDEX_QUERY_NOOUTPUT 0x0020 |
| 230187 | +#define FTS5INDEX_QUERY_SKIPHASH 0x0040 |
| 230188 | +#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080 |
| 230189 | +#define FTS5INDEX_QUERY_SCANONETERM 0x0100 |
| 228493 | 230190 | |
| 228494 | 230191 | /* |
| 228495 | 230192 | ** Create/destroy an Fts5Index object. |
| 228496 | 230193 | */ |
| 228497 | 230194 | static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); |
| | @@ -228556,10 +230253,14 @@ |
| 228556 | 230253 | static int sqlite3Fts5IterNextScan(Fts5IndexIter*); |
| 228557 | 230254 | static void *sqlite3Fts5StructureRef(Fts5Index*); |
| 228558 | 230255 | static void sqlite3Fts5StructureRelease(void*); |
| 228559 | 230256 | static int sqlite3Fts5StructureTest(Fts5Index*, void*); |
| 228560 | 230257 | |
| 230258 | +/* |
| 230259 | +** Used by xInstToken(): |
| 230260 | +*/ |
| 230261 | +static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*); |
| 228561 | 230262 | |
| 228562 | 230263 | /* |
| 228563 | 230264 | ** Insert or remove data to or from the index. Each time a document is |
| 228564 | 230265 | ** added to or removed from the index, this function is called one or more |
| 228565 | 230266 | ** times. |
| | @@ -228632,10 +230333,17 @@ |
| 228632 | 230333 | |
| 228633 | 230334 | static int sqlite3Fts5IndexLoadConfig(Fts5Index *p); |
| 228634 | 230335 | |
| 228635 | 230336 | static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin); |
| 228636 | 230337 | static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid); |
| 230338 | + |
| 230339 | +static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*); |
| 230340 | + |
| 230341 | +/* Used to populate hash tables for xInstToken in detail=none/column mode. */ |
| 230342 | +static int sqlite3Fts5IndexIterWriteTokendata( |
| 230343 | + Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff |
| 230344 | +); |
| 228637 | 230345 | |
| 228638 | 230346 | /* |
| 228639 | 230347 | ** End of interface to code in fts5_index.c. |
| 228640 | 230348 | **************************************************************************/ |
| 228641 | 230349 | |
| | @@ -228738,10 +230446,11 @@ |
| 228738 | 230446 | ); |
| 228739 | 230447 | static void sqlite3Fts5HashScanNext(Fts5Hash*); |
| 228740 | 230448 | static int sqlite3Fts5HashScanEof(Fts5Hash*); |
| 228741 | 230449 | static void sqlite3Fts5HashScanEntry(Fts5Hash *, |
| 228742 | 230450 | const char **pzTerm, /* OUT: term (nul-terminated) */ |
| 230451 | + int *pnTerm, /* OUT: Size of term in bytes */ |
| 228743 | 230452 | const u8 **ppDoclist, /* OUT: pointer to doclist */ |
| 228744 | 230453 | int *pnDoclist /* OUT: size of doclist in bytes */ |
| 228745 | 230454 | ); |
| 228746 | 230455 | |
| 228747 | 230456 | |
| | @@ -228863,10 +230572,14 @@ |
| 228863 | 230572 | static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64); |
| 228864 | 230573 | |
| 228865 | 230574 | static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**); |
| 228866 | 230575 | |
| 228867 | 230576 | static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *); |
| 230577 | + |
| 230578 | +static int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*); |
| 230579 | +static int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*); |
| 230580 | +static void sqlite3Fts5ExprClearTokens(Fts5Expr*); |
| 228868 | 230581 | |
| 228869 | 230582 | /******************************************* |
| 228870 | 230583 | ** The fts5_expr.c API above this point is used by the other hand-written |
| 228871 | 230584 | ** C code in this module. The interfaces below this point are called by |
| 228872 | 230585 | ** the parser code in fts5parse.y. */ |
| | @@ -230679,10 +232392,18 @@ |
| 230679 | 232392 | rc = fts5CInstIterNext(&p->iter); |
| 230680 | 232393 | } |
| 230681 | 232394 | } |
| 230682 | 232395 | |
| 230683 | 232396 | if( iPos==p->iRangeEnd ){ |
| 232397 | + if( p->bOpen ){ |
| 232398 | + if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){ |
| 232399 | + fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); |
| 232400 | + p->iOff = iEndOff; |
| 232401 | + } |
| 232402 | + fts5HighlightAppend(&rc, p, p->zClose, -1); |
| 232403 | + p->bOpen = 0; |
| 232404 | + } |
| 230684 | 232405 | fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); |
| 230685 | 232406 | p->iOff = iEndOff; |
| 230686 | 232407 | } |
| 230687 | 232408 | |
| 230688 | 232409 | return rc; |
| | @@ -231280,10 +233001,11 @@ |
| 231280 | 233001 | u32 nData, |
| 231281 | 233002 | const u8 *pData |
| 231282 | 233003 | ){ |
| 231283 | 233004 | if( nData ){ |
| 231284 | 233005 | if( fts5BufferGrow(pRc, pBuf, nData) ) return; |
| 233006 | + assert( pBuf->p!=0 ); |
| 231285 | 233007 | memcpy(&pBuf->p[pBuf->n], pData, nData); |
| 231286 | 233008 | pBuf->n += nData; |
| 231287 | 233009 | } |
| 231288 | 233010 | } |
| 231289 | 233011 | |
| | @@ -231381,17 +233103,19 @@ |
| 231381 | 233103 | const u8 *a, int n, /* Buffer containing poslist */ |
| 231382 | 233104 | int *pi, /* IN/OUT: Offset within a[] */ |
| 231383 | 233105 | i64 *piOff /* IN/OUT: Current offset */ |
| 231384 | 233106 | ){ |
| 231385 | 233107 | int i = *pi; |
| 233108 | + assert( a!=0 || i==0 ); |
| 231386 | 233109 | if( i>=n ){ |
| 231387 | 233110 | /* EOF */ |
| 231388 | 233111 | *piOff = -1; |
| 231389 | 233112 | return 1; |
| 231390 | 233113 | }else{ |
| 231391 | 233114 | i64 iOff = *piOff; |
| 231392 | 233115 | u32 iVal; |
| 233116 | + assert( a!=0 ); |
| 231393 | 233117 | fts5FastGetVarint32(a, i, iVal); |
| 231394 | 233118 | if( iVal<=1 ){ |
| 231395 | 233119 | if( iVal==0 ){ |
| 231396 | 233120 | *pi = i; |
| 231397 | 233121 | return 0; |
| | @@ -232018,10 +233742,20 @@ |
| 232018 | 233742 | if( (rc = fts5ConfigSetEnum(aDetail, zArg, &pConfig->eDetail)) ){ |
| 232019 | 233743 | *pzErr = sqlite3_mprintf("malformed detail=... directive"); |
| 232020 | 233744 | } |
| 232021 | 233745 | return rc; |
| 232022 | 233746 | } |
| 233747 | + |
| 233748 | + if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){ |
| 233749 | + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ |
| 233750 | + *pzErr = sqlite3_mprintf("malformed tokendata=... directive"); |
| 233751 | + rc = SQLITE_ERROR; |
| 233752 | + }else{ |
| 233753 | + pConfig->bTokendata = (zArg[0]=='1'); |
| 233754 | + } |
| 233755 | + return rc; |
| 233756 | + } |
| 232023 | 233757 | |
| 232024 | 233758 | *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd); |
| 232025 | 233759 | return SQLITE_ERROR; |
| 232026 | 233760 | } |
| 232027 | 233761 | |
| | @@ -232752,11 +234486,13 @@ |
| 232752 | 234486 | ** or term prefix. |
| 232753 | 234487 | */ |
| 232754 | 234488 | struct Fts5ExprTerm { |
| 232755 | 234489 | u8 bPrefix; /* True for a prefix term */ |
| 232756 | 234490 | u8 bFirst; /* True if token must be first in column */ |
| 232757 | | - char *zTerm; /* nul-terminated term */ |
| 234491 | + char *pTerm; /* Term data */ |
| 234492 | + int nQueryTerm; /* Effective size of term in bytes */ |
| 234493 | + int nFullTerm; /* Size of term in bytes incl. tokendata */ |
| 232758 | 234494 | Fts5IndexIter *pIter; /* Iterator for this term */ |
| 232759 | 234495 | Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */ |
| 232760 | 234496 | }; |
| 232761 | 234497 | |
| 232762 | 234498 | /* |
| | @@ -233619,11 +235355,11 @@ |
| 233619 | 235355 | if( p->pIter ){ |
| 233620 | 235356 | sqlite3Fts5IterClose(p->pIter); |
| 233621 | 235357 | p->pIter = 0; |
| 233622 | 235358 | } |
| 233623 | 235359 | rc = sqlite3Fts5IndexQuery( |
| 233624 | | - pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm), |
| 235360 | + pExpr->pIndex, p->pTerm, p->nQueryTerm, |
| 233625 | 235361 | (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | |
| 233626 | 235362 | (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), |
| 233627 | 235363 | pNear->pColset, |
| 233628 | 235364 | &p->pIter |
| 233629 | 235365 | ); |
| | @@ -234256,11 +235992,11 @@ |
| 234256 | 235992 | int i; |
| 234257 | 235993 | for(i=0; i<pPhrase->nTerm; i++){ |
| 234258 | 235994 | Fts5ExprTerm *pSyn; |
| 234259 | 235995 | Fts5ExprTerm *pNext; |
| 234260 | 235996 | Fts5ExprTerm *pTerm = &pPhrase->aTerm[i]; |
| 234261 | | - sqlite3_free(pTerm->zTerm); |
| 235997 | + sqlite3_free(pTerm->pTerm); |
| 234262 | 235998 | sqlite3Fts5IterClose(pTerm->pIter); |
| 234263 | 235999 | for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){ |
| 234264 | 236000 | pNext = pSyn->pSynonym; |
| 234265 | 236001 | sqlite3Fts5IterClose(pSyn->pIter); |
| 234266 | 236002 | fts5BufferFree((Fts5Buffer*)&pSyn[1]); |
| | @@ -234354,10 +236090,11 @@ |
| 234354 | 236090 | } |
| 234355 | 236091 | |
| 234356 | 236092 | typedef struct TokenCtx TokenCtx; |
| 234357 | 236093 | struct TokenCtx { |
| 234358 | 236094 | Fts5ExprPhrase *pPhrase; |
| 236095 | + Fts5Config *pConfig; |
| 234359 | 236096 | int rc; |
| 234360 | 236097 | }; |
| 234361 | 236098 | |
| 234362 | 236099 | /* |
| 234363 | 236100 | ** Callback for tokenizing terms used by ParseTerm(). |
| | @@ -234387,12 +236124,16 @@ |
| 234387 | 236124 | pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte); |
| 234388 | 236125 | if( pSyn==0 ){ |
| 234389 | 236126 | rc = SQLITE_NOMEM; |
| 234390 | 236127 | }else{ |
| 234391 | 236128 | memset(pSyn, 0, (size_t)nByte); |
| 234392 | | - pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); |
| 234393 | | - memcpy(pSyn->zTerm, pToken, nToken); |
| 236129 | + pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); |
| 236130 | + pSyn->nFullTerm = pSyn->nQueryTerm = nToken; |
| 236131 | + if( pCtx->pConfig->bTokendata ){ |
| 236132 | + pSyn->nQueryTerm = (int)strlen(pSyn->pTerm); |
| 236133 | + } |
| 236134 | + memcpy(pSyn->pTerm, pToken, nToken); |
| 234394 | 236135 | pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; |
| 234395 | 236136 | pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; |
| 234396 | 236137 | } |
| 234397 | 236138 | }else{ |
| 234398 | 236139 | Fts5ExprTerm *pTerm; |
| | @@ -234413,11 +236154,15 @@ |
| 234413 | 236154 | } |
| 234414 | 236155 | |
| 234415 | 236156 | if( rc==SQLITE_OK ){ |
| 234416 | 236157 | pTerm = &pPhrase->aTerm[pPhrase->nTerm++]; |
| 234417 | 236158 | memset(pTerm, 0, sizeof(Fts5ExprTerm)); |
| 234418 | | - pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); |
| 236159 | + pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken); |
| 236160 | + pTerm->nFullTerm = pTerm->nQueryTerm = nToken; |
| 236161 | + if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){ |
| 236162 | + pTerm->nQueryTerm = (int)strlen(pTerm->pTerm); |
| 236163 | + } |
| 234419 | 236164 | } |
| 234420 | 236165 | } |
| 234421 | 236166 | |
| 234422 | 236167 | pCtx->rc = rc; |
| 234423 | 236168 | return rc; |
| | @@ -234480,10 +236225,11 @@ |
| 234480 | 236225 | int rc; /* Tokenize return code */ |
| 234481 | 236226 | char *z = 0; |
| 234482 | 236227 | |
| 234483 | 236228 | memset(&sCtx, 0, sizeof(TokenCtx)); |
| 234484 | 236229 | sCtx.pPhrase = pAppend; |
| 236230 | + sCtx.pConfig = pConfig; |
| 234485 | 236231 | |
| 234486 | 236232 | rc = fts5ParseStringFromToken(pToken, &z); |
| 234487 | 236233 | if( rc==SQLITE_OK ){ |
| 234488 | 236234 | int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0); |
| 234489 | 236235 | int n; |
| | @@ -234529,12 +236275,11 @@ |
| 234529 | 236275 | Fts5Expr **ppNew |
| 234530 | 236276 | ){ |
| 234531 | 236277 | int rc = SQLITE_OK; /* Return code */ |
| 234532 | 236278 | Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */ |
| 234533 | 236279 | Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ |
| 234534 | | - TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */ |
| 234535 | | - |
| 236280 | + TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */ |
| 234536 | 236281 | pOrig = pExpr->apExprPhrase[iPhrase]; |
| 234537 | 236282 | pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr)); |
| 234538 | 236283 | if( rc==SQLITE_OK ){ |
| 234539 | 236284 | pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, |
| 234540 | 236285 | sizeof(Fts5ExprPhrase*)); |
| | @@ -234561,17 +236306,16 @@ |
| 234561 | 236306 | } |
| 234562 | 236307 | } |
| 234563 | 236308 | |
| 234564 | 236309 | if( pOrig->nTerm ){ |
| 234565 | 236310 | int i; /* Used to iterate through phrase terms */ |
| 236311 | + sCtx.pConfig = pExpr->pConfig; |
| 234566 | 236312 | for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){ |
| 234567 | 236313 | int tflags = 0; |
| 234568 | 236314 | Fts5ExprTerm *p; |
| 234569 | 236315 | for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){ |
| 234570 | | - const char *zTerm = p->zTerm; |
| 234571 | | - rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm), |
| 234572 | | - 0, 0); |
| 236316 | + rc = fts5ParseTokenize((void*)&sCtx, tflags, p->pTerm,p->nFullTerm,0,0); |
| 234573 | 236317 | tflags = FTS5_TOKEN_COLOCATED; |
| 234574 | 236318 | } |
| 234575 | 236319 | if( rc==SQLITE_OK ){ |
| 234576 | 236320 | sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix; |
| 234577 | 236321 | sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst; |
| | @@ -234948,15 +236692,17 @@ |
| 234948 | 236692 | ); |
| 234949 | 236693 | if( pPhrase ){ |
| 234950 | 236694 | if( parseGrowPhraseArray(pParse) ){ |
| 234951 | 236695 | fts5ExprPhraseFree(pPhrase); |
| 234952 | 236696 | }else{ |
| 236697 | + Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii]; |
| 236698 | + Fts5ExprTerm *pTo = &pPhrase->aTerm[0]; |
| 234953 | 236699 | pParse->apPhrase[pParse->nPhrase++] = pPhrase; |
| 234954 | 236700 | pPhrase->nTerm = 1; |
| 234955 | | - pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( |
| 234956 | | - &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 |
| 234957 | | - ); |
| 236701 | + pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm); |
| 236702 | + pTo->nQueryTerm = p->nQueryTerm; |
| 236703 | + pTo->nFullTerm = p->nFullTerm; |
| 234958 | 236704 | pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, |
| 234959 | 236705 | 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) |
| 234960 | 236706 | ); |
| 234961 | 236707 | } |
| 234962 | 236708 | } |
| | @@ -235137,20 +236883,21 @@ |
| 235137 | 236883 | Fts5ExprTerm *p; |
| 235138 | 236884 | char *zQuoted; |
| 235139 | 236885 | |
| 235140 | 236886 | /* Determine the maximum amount of space required. */ |
| 235141 | 236887 | for(p=pTerm; p; p=p->pSynonym){ |
| 235142 | | - nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2; |
| 236888 | + nByte += pTerm->nQueryTerm * 2 + 3 + 2; |
| 235143 | 236889 | } |
| 235144 | 236890 | zQuoted = sqlite3_malloc64(nByte); |
| 235145 | 236891 | |
| 235146 | 236892 | if( zQuoted ){ |
| 235147 | 236893 | int i = 0; |
| 235148 | 236894 | for(p=pTerm; p; p=p->pSynonym){ |
| 235149 | | - char *zIn = p->zTerm; |
| 236895 | + char *zIn = p->pTerm; |
| 236896 | + char *zEnd = &zIn[p->nQueryTerm]; |
| 235150 | 236897 | zQuoted[i++] = '"'; |
| 235151 | | - while( *zIn ){ |
| 236898 | + while( zIn<zEnd ){ |
| 235152 | 236899 | if( *zIn=='"' ) zQuoted[i++] = '"'; |
| 235153 | 236900 | zQuoted[i++] = *zIn++; |
| 235154 | 236901 | } |
| 235155 | 236902 | zQuoted[i++] = '"'; |
| 235156 | 236903 | if( p->pSynonym ) zQuoted[i++] = '|'; |
| | @@ -235224,12 +236971,14 @@ |
| 235224 | 236971 | for(i=0; i<pNear->nPhrase; i++){ |
| 235225 | 236972 | Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; |
| 235226 | 236973 | |
| 235227 | 236974 | zRet = fts5PrintfAppend(zRet, " {"); |
| 235228 | 236975 | for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){ |
| 235229 | | - char *zTerm = pPhrase->aTerm[iTerm].zTerm; |
| 235230 | | - zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm); |
| 236976 | + Fts5ExprTerm *p = &pPhrase->aTerm[iTerm]; |
| 236977 | + zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ", |
| 236978 | + p->nQueryTerm, p->pTerm |
| 236979 | + ); |
| 235231 | 236980 | if( pPhrase->aTerm[iTerm].bPrefix ){ |
| 235232 | 236981 | zRet = fts5PrintfAppend(zRet, "*"); |
| 235233 | 236982 | } |
| 235234 | 236983 | } |
| 235235 | 236984 | |
| | @@ -235625,10 +237374,21 @@ |
| 235625 | 237374 | for(i=0; i<pColset->nCol; i++){ |
| 235626 | 237375 | if( pColset->aiCol[i]==iCol ) return 1; |
| 235627 | 237376 | } |
| 235628 | 237377 | return 0; |
| 235629 | 237378 | } |
| 237379 | + |
| 237380 | +/* |
| 237381 | +** pToken is a buffer nToken bytes in size that may or may not contain |
| 237382 | +** an embedded 0x00 byte. If it does, return the number of bytes in |
| 237383 | +** the buffer before the 0x00. If it does not, return nToken. |
| 237384 | +*/ |
| 237385 | +static int fts5QueryTerm(const char *pToken, int nToken){ |
| 237386 | + int ii; |
| 237387 | + for(ii=0; ii<nToken && pToken[ii]; ii++){} |
| 237388 | + return ii; |
| 237389 | +} |
| 235630 | 237390 | |
| 235631 | 237391 | static int fts5ExprPopulatePoslistsCb( |
| 235632 | 237392 | void *pCtx, /* Copy of 2nd argument to xTokenize() */ |
| 235633 | 237393 | int tflags, /* Mask of FTS5_TOKEN_* flags */ |
| 235634 | 237394 | const char *pToken, /* Pointer to buffer containing token */ |
| | @@ -235637,26 +237397,37 @@ |
| 235637 | 237397 | int iUnused2 /* Byte offset of end of token within input text */ |
| 235638 | 237398 | ){ |
| 235639 | 237399 | Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx; |
| 235640 | 237400 | Fts5Expr *pExpr = p->pExpr; |
| 235641 | 237401 | int i; |
| 237402 | + int nQuery = nToken; |
| 237403 | + i64 iRowid = pExpr->pRoot->iRowid; |
| 235642 | 237404 | |
| 235643 | 237405 | UNUSED_PARAM2(iUnused1, iUnused2); |
| 235644 | 237406 | |
| 235645 | | - if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE; |
| 237407 | + if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE; |
| 237408 | + if( pExpr->pConfig->bTokendata ){ |
| 237409 | + nQuery = fts5QueryTerm(pToken, nQuery); |
| 237410 | + } |
| 235646 | 237411 | if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++; |
| 235647 | 237412 | for(i=0; i<pExpr->nPhrase; i++){ |
| 235648 | | - Fts5ExprTerm *pTerm; |
| 237413 | + Fts5ExprTerm *pT; |
| 235649 | 237414 | if( p->aPopulator[i].bOk==0 ) continue; |
| 235650 | | - for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){ |
| 235651 | | - int nTerm = (int)strlen(pTerm->zTerm); |
| 235652 | | - if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix)) |
| 235653 | | - && memcmp(pTerm->zTerm, pToken, nTerm)==0 |
| 237415 | + for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){ |
| 237416 | + if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix)) |
| 237417 | + && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0 |
| 235654 | 237418 | ){ |
| 235655 | 237419 | int rc = sqlite3Fts5PoslistWriterAppend( |
| 235656 | 237420 | &pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff |
| 235657 | 237421 | ); |
| 237422 | + if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){ |
| 237423 | + int iCol = p->iOff>>32; |
| 237424 | + int iTokOff = p->iOff & 0x7FFFFFFF; |
| 237425 | + rc = sqlite3Fts5IndexIterWriteTokendata( |
| 237426 | + pT->pIter, pToken, nToken, iRowid, iCol, iTokOff |
| 237427 | + ); |
| 237428 | + } |
| 235658 | 237429 | if( rc ) return rc; |
| 235659 | 237430 | break; |
| 235660 | 237431 | } |
| 235661 | 237432 | } |
| 235662 | 237433 | } |
| | @@ -235787,10 +237558,87 @@ |
| 235787 | 237558 | *pnCollist = 0; |
| 235788 | 237559 | } |
| 235789 | 237560 | |
| 235790 | 237561 | return rc; |
| 235791 | 237562 | } |
| 237563 | + |
| 237564 | +/* |
| 237565 | +** Does the work of the fts5_api.xQueryToken() API method. |
| 237566 | +*/ |
| 237567 | +static int sqlite3Fts5ExprQueryToken( |
| 237568 | + Fts5Expr *pExpr, |
| 237569 | + int iPhrase, |
| 237570 | + int iToken, |
| 237571 | + const char **ppOut, |
| 237572 | + int *pnOut |
| 237573 | +){ |
| 237574 | + Fts5ExprPhrase *pPhrase = 0; |
| 237575 | + |
| 237576 | + if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ |
| 237577 | + return SQLITE_RANGE; |
| 237578 | + } |
| 237579 | + pPhrase = pExpr->apExprPhrase[iPhrase]; |
| 237580 | + if( iToken<0 || iToken>=pPhrase->nTerm ){ |
| 237581 | + return SQLITE_RANGE; |
| 237582 | + } |
| 237583 | + |
| 237584 | + *ppOut = pPhrase->aTerm[iToken].pTerm; |
| 237585 | + *pnOut = pPhrase->aTerm[iToken].nFullTerm; |
| 237586 | + return SQLITE_OK; |
| 237587 | +} |
| 237588 | + |
| 237589 | +/* |
| 237590 | +** Does the work of the fts5_api.xInstToken() API method. |
| 237591 | +*/ |
| 237592 | +static int sqlite3Fts5ExprInstToken( |
| 237593 | + Fts5Expr *pExpr, |
| 237594 | + i64 iRowid, |
| 237595 | + int iPhrase, |
| 237596 | + int iCol, |
| 237597 | + int iOff, |
| 237598 | + int iToken, |
| 237599 | + const char **ppOut, |
| 237600 | + int *pnOut |
| 237601 | +){ |
| 237602 | + Fts5ExprPhrase *pPhrase = 0; |
| 237603 | + Fts5ExprTerm *pTerm = 0; |
| 237604 | + int rc = SQLITE_OK; |
| 237605 | + |
| 237606 | + if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ |
| 237607 | + return SQLITE_RANGE; |
| 237608 | + } |
| 237609 | + pPhrase = pExpr->apExprPhrase[iPhrase]; |
| 237610 | + if( iToken<0 || iToken>=pPhrase->nTerm ){ |
| 237611 | + return SQLITE_RANGE; |
| 237612 | + } |
| 237613 | + pTerm = &pPhrase->aTerm[iToken]; |
| 237614 | + if( pTerm->bPrefix==0 ){ |
| 237615 | + if( pExpr->pConfig->bTokendata ){ |
| 237616 | + rc = sqlite3Fts5IterToken( |
| 237617 | + pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut |
| 237618 | + ); |
| 237619 | + }else{ |
| 237620 | + *ppOut = pTerm->pTerm; |
| 237621 | + *pnOut = pTerm->nFullTerm; |
| 237622 | + } |
| 237623 | + } |
| 237624 | + return rc; |
| 237625 | +} |
| 237626 | + |
| 237627 | +/* |
| 237628 | +** Clear the token mappings for all Fts5IndexIter objects mannaged by |
| 237629 | +** the expression passed as the only argument. |
| 237630 | +*/ |
| 237631 | +static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){ |
| 237632 | + int ii; |
| 237633 | + for(ii=0; ii<pExpr->nPhrase; ii++){ |
| 237634 | + Fts5ExprTerm *pT; |
| 237635 | + for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){ |
| 237636 | + sqlite3Fts5IndexIterClearTokendata(pT->pIter); |
| 237637 | + } |
| 237638 | + } |
| 237639 | +} |
| 235792 | 237640 | |
| 235793 | 237641 | /* |
| 235794 | 237642 | ** 2014 August 11 |
| 235795 | 237643 | ** |
| 235796 | 237644 | ** The author disclaims copyright to this source code. In place of |
| | @@ -235826,14 +237674,19 @@ |
| 235826 | 237674 | Fts5HashEntry **aSlot; /* Array of hash slots */ |
| 235827 | 237675 | }; |
| 235828 | 237676 | |
| 235829 | 237677 | /* |
| 235830 | 237678 | ** Each entry in the hash table is represented by an object of the |
| 235831 | | -** following type. Each object, its key (a nul-terminated string) and |
| 235832 | | -** its current data are stored in a single memory allocation. The |
| 235833 | | -** key immediately follows the object in memory. The position list |
| 235834 | | -** data immediately follows the key data in memory. |
| 237679 | +** following type. Each object, its key, and its current data are stored |
| 237680 | +** in a single memory allocation. The key immediately follows the object |
| 237681 | +** in memory. The position list data immediately follows the key data |
| 237682 | +** in memory. |
| 237683 | +** |
| 237684 | +** The key is Fts5HashEntry.nKey bytes in size. It consists of a single |
| 237685 | +** byte identifying the index (either the main term index or a prefix-index), |
| 237686 | +** followed by the term data. For example: "0token". There is no |
| 237687 | +** nul-terminator - in this case nKey=6. |
| 235835 | 237688 | ** |
| 235836 | 237689 | ** The data that follows the key is in a similar, but not identical format |
| 235837 | 237690 | ** to the doclist data stored in the database. It is: |
| 235838 | 237691 | ** |
| 235839 | 237692 | ** * Rowid, as a varint |
| | @@ -235964,12 +237817,11 @@ |
| 235964 | 237817 | for(i=0; i<pHash->nSlot; i++){ |
| 235965 | 237818 | while( apOld[i] ){ |
| 235966 | 237819 | unsigned int iHash; |
| 235967 | 237820 | Fts5HashEntry *p = apOld[i]; |
| 235968 | 237821 | apOld[i] = p->pHashNext; |
| 235969 | | - iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), |
| 235970 | | - (int)strlen(fts5EntryKey(p))); |
| 237822 | + iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey); |
| 235971 | 237823 | p->pHashNext = apNew[iHash]; |
| 235972 | 237824 | apNew[iHash] = p; |
| 235973 | 237825 | } |
| 235974 | 237826 | } |
| 235975 | 237827 | |
| | @@ -236049,11 +237901,11 @@ |
| 236049 | 237901 | /* Attempt to locate an existing hash entry */ |
| 236050 | 237902 | iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken); |
| 236051 | 237903 | for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
| 236052 | 237904 | char *zKey = fts5EntryKey(p); |
| 236053 | 237905 | if( zKey[0]==bByte |
| 236054 | | - && p->nKey==nToken |
| 237906 | + && p->nKey==nToken+1 |
| 236055 | 237907 | && memcmp(&zKey[1], pToken, nToken)==0 |
| 236056 | 237908 | ){ |
| 236057 | 237909 | break; |
| 236058 | 237910 | } |
| 236059 | 237911 | } |
| | @@ -236079,13 +237931,13 @@ |
| 236079 | 237931 | p->nAlloc = (int)nByte; |
| 236080 | 237932 | zKey = fts5EntryKey(p); |
| 236081 | 237933 | zKey[0] = bByte; |
| 236082 | 237934 | memcpy(&zKey[1], pToken, nToken); |
| 236083 | 237935 | assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) ); |
| 236084 | | - p->nKey = nToken; |
| 237936 | + p->nKey = nToken+1; |
| 236085 | 237937 | zKey[nToken+1] = '\0'; |
| 236086 | | - p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry); |
| 237938 | + p->nData = nToken+1 + sizeof(Fts5HashEntry); |
| 236087 | 237939 | p->pHashNext = pHash->aSlot[iHash]; |
| 236088 | 237940 | pHash->aSlot[iHash] = p; |
| 236089 | 237941 | pHash->nEntry++; |
| 236090 | 237942 | |
| 236091 | 237943 | /* Add the first rowid field to the hash-entry */ |
| | @@ -236198,16 +238050,21 @@ |
| 236198 | 238050 | p2 = 0; |
| 236199 | 238051 | }else if( p2==0 ){ |
| 236200 | 238052 | *ppOut = p1; |
| 236201 | 238053 | p1 = 0; |
| 236202 | 238054 | }else{ |
| 236203 | | - int i = 0; |
| 236204 | 238055 | char *zKey1 = fts5EntryKey(p1); |
| 236205 | 238056 | char *zKey2 = fts5EntryKey(p2); |
| 236206 | | - while( zKey1[i]==zKey2[i] ) i++; |
| 238057 | + int nMin = MIN(p1->nKey, p2->nKey); |
| 236207 | 238058 | |
| 236208 | | - if( ((u8)zKey1[i])>((u8)zKey2[i]) ){ |
| 238059 | + int cmp = memcmp(zKey1, zKey2, nMin); |
| 238060 | + if( cmp==0 ){ |
| 238061 | + cmp = p1->nKey - p2->nKey; |
| 238062 | + } |
| 238063 | + assert( cmp!=0 ); |
| 238064 | + |
| 238065 | + if( cmp>0 ){ |
| 236209 | 238066 | /* p2 is smaller */ |
| 236210 | 238067 | *ppOut = p2; |
| 236211 | 238068 | ppOut = &p2->pScanNext; |
| 236212 | 238069 | p2 = p2->pScanNext; |
| 236213 | 238070 | }else{ |
| | @@ -236245,11 +238102,11 @@ |
| 236245 | 238102 | |
| 236246 | 238103 | for(iSlot=0; iSlot<pHash->nSlot; iSlot++){ |
| 236247 | 238104 | Fts5HashEntry *pIter; |
| 236248 | 238105 | for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ |
| 236249 | 238106 | if( pTerm==0 |
| 236250 | | - || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) |
| 238107 | + || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) |
| 236251 | 238108 | ){ |
| 236252 | 238109 | Fts5HashEntry *pEntry = pIter; |
| 236253 | 238110 | pEntry->pScanNext = 0; |
| 236254 | 238111 | for(i=0; ap[i]; i++){ |
| 236255 | 238112 | pEntry = fts5HashEntryMerge(pEntry, ap[i]); |
| | @@ -236284,16 +238141,15 @@ |
| 236284 | 238141 | char *zKey = 0; |
| 236285 | 238142 | Fts5HashEntry *p; |
| 236286 | 238143 | |
| 236287 | 238144 | for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){ |
| 236288 | 238145 | zKey = fts5EntryKey(p); |
| 236289 | | - assert( p->nKey+1==(int)strlen(zKey) ); |
| 236290 | | - if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break; |
| 238146 | + if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break; |
| 236291 | 238147 | } |
| 236292 | 238148 | |
| 236293 | 238149 | if( p ){ |
| 236294 | | - int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; |
| 238150 | + int nHashPre = sizeof(Fts5HashEntry) + nTerm; |
| 236295 | 238151 | int nList = p->nData - nHashPre; |
| 236296 | 238152 | u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); |
| 236297 | 238153 | if( pRet ){ |
| 236298 | 238154 | Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; |
| 236299 | 238155 | memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); |
| | @@ -236350,23 +238206,26 @@ |
| 236350 | 238206 | } |
| 236351 | 238207 | |
| 236352 | 238208 | static void sqlite3Fts5HashScanEntry( |
| 236353 | 238209 | Fts5Hash *pHash, |
| 236354 | 238210 | const char **pzTerm, /* OUT: term (nul-terminated) */ |
| 238211 | + int *pnTerm, /* OUT: Size of term in bytes */ |
| 236355 | 238212 | const u8 **ppDoclist, /* OUT: pointer to doclist */ |
| 236356 | 238213 | int *pnDoclist /* OUT: size of doclist in bytes */ |
| 236357 | 238214 | ){ |
| 236358 | 238215 | Fts5HashEntry *p; |
| 236359 | 238216 | if( (p = pHash->pScan) ){ |
| 236360 | 238217 | char *zKey = fts5EntryKey(p); |
| 236361 | | - int nTerm = (int)strlen(zKey); |
| 238218 | + int nTerm = p->nKey; |
| 236362 | 238219 | fts5HashAddPoslistSize(pHash, p, 0); |
| 236363 | 238220 | *pzTerm = zKey; |
| 236364 | | - *ppDoclist = (const u8*)&zKey[nTerm+1]; |
| 236365 | | - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); |
| 238221 | + *pnTerm = nTerm; |
| 238222 | + *ppDoclist = (const u8*)&zKey[nTerm]; |
| 238223 | + *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm); |
| 236366 | 238224 | }else{ |
| 236367 | 238225 | *pzTerm = 0; |
| 238226 | + *pnTerm = 0; |
| 236368 | 238227 | *ppDoclist = 0; |
| 236369 | 238228 | *pnDoclist = 0; |
| 236370 | 238229 | } |
| 236371 | 238230 | } |
| 236372 | 238231 | |
| | @@ -236693,10 +238552,13 @@ |
| 236693 | 238552 | typedef struct Fts5DoclistIter Fts5DoclistIter; |
| 236694 | 238553 | typedef struct Fts5SegWriter Fts5SegWriter; |
| 236695 | 238554 | typedef struct Fts5Structure Fts5Structure; |
| 236696 | 238555 | typedef struct Fts5StructureLevel Fts5StructureLevel; |
| 236697 | 238556 | typedef struct Fts5StructureSegment Fts5StructureSegment; |
| 238557 | +typedef struct Fts5TokenDataIter Fts5TokenDataIter; |
| 238558 | +typedef struct Fts5TokenDataMap Fts5TokenDataMap; |
| 238559 | +typedef struct Fts5TombstoneArray Fts5TombstoneArray; |
| 236698 | 238560 | |
| 236699 | 238561 | struct Fts5Data { |
| 236700 | 238562 | u8 *p; /* Pointer to buffer containing record */ |
| 236701 | 238563 | int nn; /* Size of record in bytes */ |
| 236702 | 238564 | int szLeaf; /* Size of leaf without page-index */ |
| | @@ -236727,18 +238589,20 @@ |
| 236727 | 238589 | int nContentlessDelete; /* Number of contentless delete ops */ |
| 236728 | 238590 | int nPendingRow; /* Number of INSERT in hash table */ |
| 236729 | 238591 | |
| 236730 | 238592 | /* Error state. */ |
| 236731 | 238593 | int rc; /* Current error code */ |
| 238594 | + int flushRc; |
| 236732 | 238595 | |
| 236733 | 238596 | /* State used by the fts5DataXXX() functions. */ |
| 236734 | 238597 | sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ |
| 236735 | 238598 | sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ |
| 236736 | 238599 | sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ |
| 236737 | 238600 | sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ |
| 236738 | 238601 | sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */ |
| 236739 | 238602 | sqlite3_stmt *pIdxSelect; |
| 238603 | + sqlite3_stmt *pIdxNextSelect; |
| 236740 | 238604 | int nRead; /* Total number of blocks read */ |
| 236741 | 238605 | |
| 236742 | 238606 | sqlite3_stmt *pDeleteFromIdx; |
| 236743 | 238607 | |
| 236744 | 238608 | sqlite3_stmt *pDataVersion; |
| | @@ -236888,12 +238752,11 @@ |
| 236888 | 238752 | int flags; /* Mask of configuration flags */ |
| 236889 | 238753 | int iLeafPgno; /* Current leaf page number */ |
| 236890 | 238754 | Fts5Data *pLeaf; /* Current leaf data */ |
| 236891 | 238755 | Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */ |
| 236892 | 238756 | i64 iLeafOffset; /* Byte offset within current leaf */ |
| 236893 | | - Fts5Data **apTombstone; /* Array of tombstone pages */ |
| 236894 | | - int nTombstone; |
| 238757 | + Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */ |
| 236895 | 238758 | |
| 236896 | 238759 | /* Next method */ |
| 236897 | 238760 | void (*xNext)(Fts5Index*, Fts5SegIter*, int*); |
| 236898 | 238761 | |
| 236899 | 238762 | /* The page and offset from which the current term was read. The offset |
| | @@ -236915,10 +238778,19 @@ |
| 236915 | 238778 | Fts5Buffer term; /* Current term */ |
| 236916 | 238779 | i64 iRowid; /* Current rowid */ |
| 236917 | 238780 | int nPos; /* Number of bytes in current position list */ |
| 236918 | 238781 | u8 bDel; /* True if the delete flag is set */ |
| 236919 | 238782 | }; |
| 238783 | + |
| 238784 | +/* |
| 238785 | +** Array of tombstone pages. Reference counted. |
| 238786 | +*/ |
| 238787 | +struct Fts5TombstoneArray { |
| 238788 | + int nRef; /* Number of pointers to this object */ |
| 238789 | + int nTombstone; |
| 238790 | + Fts5Data *apTombstone[1]; /* Array of tombstone pages */ |
| 238791 | +}; |
| 236920 | 238792 | |
| 236921 | 238793 | /* |
| 236922 | 238794 | ** Argument is a pointer to an Fts5Data structure that contains a |
| 236923 | 238795 | ** leaf page. |
| 236924 | 238796 | */ |
| | @@ -236960,13 +238832,20 @@ |
| 236960 | 238832 | ** the smallest key overall. aFirst[0] is unused. |
| 236961 | 238833 | ** |
| 236962 | 238834 | ** poslist: |
| 236963 | 238835 | ** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered. |
| 236964 | 238836 | ** There is no way to tell if this is populated or not. |
| 238837 | +** |
| 238838 | +** pColset: |
| 238839 | +** If not NULL, points to an object containing a set of column indices. |
| 238840 | +** Only matches that occur in one of these columns will be returned. |
| 238841 | +** The Fts5Iter does not own the Fts5Colset object, and so it is not |
| 238842 | +** freed when the iterator is closed - it is owned by the upper layer. |
| 236965 | 238843 | */ |
| 236966 | 238844 | struct Fts5Iter { |
| 236967 | 238845 | Fts5IndexIter base; /* Base class containing output vars */ |
| 238846 | + Fts5TokenDataIter *pTokenDataIter; |
| 236968 | 238847 | |
| 236969 | 238848 | Fts5Index *pIndex; /* Index that owns this iterator */ |
| 236970 | 238849 | Fts5Buffer poslist; /* Buffer containing current poslist */ |
| 236971 | 238850 | Fts5Colset *pColset; /* Restrict matches to these columns */ |
| 236972 | 238851 | |
| | @@ -236979,11 +238858,10 @@ |
| 236979 | 238858 | |
| 236980 | 238859 | i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ |
| 236981 | 238860 | Fts5CResult *aFirst; /* Current merge state (see above) */ |
| 236982 | 238861 | Fts5SegIter aSeg[1]; /* Array of segment iterators */ |
| 236983 | 238862 | }; |
| 236984 | | - |
| 236985 | 238863 | |
| 236986 | 238864 | /* |
| 236987 | 238865 | ** An instance of the following type is used to iterate through the contents |
| 236988 | 238866 | ** of a doclist-index record. |
| 236989 | 238867 | ** |
| | @@ -238279,22 +240157,24 @@ |
| 238279 | 240157 | pIter->xNext = fts5SegIterNext; |
| 238280 | 240158 | } |
| 238281 | 240159 | } |
| 238282 | 240160 | |
| 238283 | 240161 | /* |
| 238284 | | -** Allocate a tombstone hash page array (pIter->apTombstone) for the |
| 238285 | | -** iterator passed as the second argument. If an OOM error occurs, leave |
| 238286 | | -** an error in the Fts5Index object. |
| 240162 | +** Allocate a tombstone hash page array object (pIter->pTombArray) for |
| 240163 | +** the iterator passed as the second argument. If an OOM error occurs, |
| 240164 | +** leave an error in the Fts5Index object. |
| 238287 | 240165 | */ |
| 238288 | 240166 | static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){ |
| 238289 | 240167 | const int nTomb = pIter->pSeg->nPgTombstone; |
| 238290 | 240168 | if( nTomb>0 ){ |
| 238291 | | - Fts5Data **apTomb = 0; |
| 238292 | | - apTomb = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data)*nTomb); |
| 238293 | | - if( apTomb ){ |
| 238294 | | - pIter->apTombstone = apTomb; |
| 238295 | | - pIter->nTombstone = nTomb; |
| 240169 | + int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray); |
| 240170 | + Fts5TombstoneArray *pNew; |
| 240171 | + pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte); |
| 240172 | + if( pNew ){ |
| 240173 | + pNew->nTombstone = nTomb; |
| 240174 | + pNew->nRef = 1; |
| 240175 | + pIter->pTombArray = pNew; |
| 238296 | 240176 | } |
| 238297 | 240177 | } |
| 238298 | 240178 | } |
| 238299 | 240179 | |
| 238300 | 240180 | /* |
| | @@ -238547,19 +240427,20 @@ |
| 238547 | 240427 | pIter->iLeafOffset = iOff; |
| 238548 | 240428 | fts5SegIterLoadTerm(p, pIter, nKeep); |
| 238549 | 240429 | }else{ |
| 238550 | 240430 | const u8 *pList = 0; |
| 238551 | 240431 | const char *zTerm = 0; |
| 240432 | + int nTerm = 0; |
| 238552 | 240433 | int nList; |
| 238553 | 240434 | sqlite3Fts5HashScanNext(p->pHash); |
| 238554 | | - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); |
| 240435 | + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); |
| 238555 | 240436 | if( pList==0 ) goto next_none_eof; |
| 238556 | 240437 | pIter->pLeaf->p = (u8*)pList; |
| 238557 | 240438 | pIter->pLeaf->nn = nList; |
| 238558 | 240439 | pIter->pLeaf->szLeaf = nList; |
| 238559 | 240440 | pIter->iEndofDoclist = nList; |
| 238560 | | - sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm); |
| 240441 | + sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm); |
| 238561 | 240442 | pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); |
| 238562 | 240443 | } |
| 238563 | 240444 | |
| 238564 | 240445 | if( pbNewTerm ) *pbNewTerm = 1; |
| 238565 | 240446 | }else{ |
| | @@ -238621,26 +240502,26 @@ |
| 238621 | 240502 | pIter->iLeafOffset = iOff; |
| 238622 | 240503 | |
| 238623 | 240504 | }else if( pIter->pSeg==0 ){ |
| 238624 | 240505 | const u8 *pList = 0; |
| 238625 | 240506 | const char *zTerm = 0; |
| 240507 | + int nTerm = 0; |
| 238626 | 240508 | int nList = 0; |
| 238627 | 240509 | assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm ); |
| 238628 | 240510 | if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){ |
| 238629 | 240511 | sqlite3Fts5HashScanNext(p->pHash); |
| 238630 | | - sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList); |
| 240512 | + sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList); |
| 238631 | 240513 | } |
| 238632 | 240514 | if( pList==0 ){ |
| 238633 | 240515 | fts5DataRelease(pIter->pLeaf); |
| 238634 | 240516 | pIter->pLeaf = 0; |
| 238635 | 240517 | }else{ |
| 238636 | 240518 | pIter->pLeaf->p = (u8*)pList; |
| 238637 | 240519 | pIter->pLeaf->nn = nList; |
| 238638 | 240520 | pIter->pLeaf->szLeaf = nList; |
| 238639 | 240521 | pIter->iEndofDoclist = nList+1; |
| 238640 | | - sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm), |
| 238641 | | - (u8*)zTerm); |
| 240522 | + sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm); |
| 238642 | 240523 | pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid); |
| 238643 | 240524 | *pbNewTerm = 1; |
| 238644 | 240525 | } |
| 238645 | 240526 | }else{ |
| 238646 | 240527 | iOff = 0; |
| | @@ -239022,11 +240903,11 @@ |
| 239022 | 240903 | |
| 239023 | 240904 | if( pIter->pLeaf ){ |
| 239024 | 240905 | fts5LeafSeek(p, bGe, pIter, pTerm, nTerm); |
| 239025 | 240906 | } |
| 239026 | 240907 | |
| 239027 | | - if( p->rc==SQLITE_OK && bGe==0 ){ |
| 240908 | + if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){ |
| 239028 | 240909 | pIter->flags |= FTS5_SEGITER_ONETERM; |
| 239029 | 240910 | if( pIter->pLeaf ){ |
| 239030 | 240911 | if( flags & FTS5INDEX_QUERY_DESC ){ |
| 239031 | 240912 | pIter->flags |= FTS5_SEGITER_REVERSE; |
| 239032 | 240913 | } |
| | @@ -239038,11 +240919,13 @@ |
| 239038 | 240919 | } |
| 239039 | 240920 | } |
| 239040 | 240921 | } |
| 239041 | 240922 | |
| 239042 | 240923 | fts5SegIterSetNext(p, pIter); |
| 239043 | | - fts5SegIterAllocTombstone(p, pIter); |
| 240924 | + if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){ |
| 240925 | + fts5SegIterAllocTombstone(p, pIter); |
| 240926 | + } |
| 239044 | 240927 | |
| 239045 | 240928 | /* Either: |
| 239046 | 240929 | ** |
| 239047 | 240930 | ** 1) an error has occurred, or |
| 239048 | 240931 | ** 2) the iterator points to EOF, or |
| | @@ -239055,10 +240938,83 @@ |
| 239055 | 240938 | || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */ |
| 239056 | 240939 | || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */ |
| 239057 | 240940 | ); |
| 239058 | 240941 | } |
| 239059 | 240942 | |
| 240943 | + |
| 240944 | +/* |
| 240945 | +** SQL used by fts5SegIterNextInit() to find the page to open. |
| 240946 | +*/ |
| 240947 | +static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){ |
| 240948 | + if( p->pIdxNextSelect==0 ){ |
| 240949 | + Fts5Config *pConfig = p->pConfig; |
| 240950 | + fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlite3_mprintf( |
| 240951 | + "SELECT pgno FROM '%q'.'%q_idx' WHERE " |
| 240952 | + "segid=? AND term>? ORDER BY term ASC LIMIT 1", |
| 240953 | + pConfig->zDb, pConfig->zName |
| 240954 | + )); |
| 240955 | + |
| 240956 | + } |
| 240957 | + return p->pIdxNextSelect; |
| 240958 | +} |
| 240959 | + |
| 240960 | +/* |
| 240961 | +** This is similar to fts5SegIterSeekInit(), except that it initializes |
| 240962 | +** the segment iterator to point to the first term following the page |
| 240963 | +** with pToken/nToken on it. |
| 240964 | +*/ |
| 240965 | +static void fts5SegIterNextInit( |
| 240966 | + Fts5Index *p, |
| 240967 | + const char *pTerm, int nTerm, |
| 240968 | + Fts5StructureSegment *pSeg, /* Description of segment */ |
| 240969 | + Fts5SegIter *pIter /* Object to populate */ |
| 240970 | +){ |
| 240971 | + int iPg = -1; /* Page of segment to open */ |
| 240972 | + int bDlidx = 0; |
| 240973 | + sqlite3_stmt *pSel = 0; /* SELECT to find iPg */ |
| 240974 | + |
| 240975 | + pSel = fts5IdxNextStmt(p); |
| 240976 | + if( pSel ){ |
| 240977 | + assert( p->rc==SQLITE_OK ); |
| 240978 | + sqlite3_bind_int(pSel, 1, pSeg->iSegid); |
| 240979 | + sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC); |
| 240980 | + |
| 240981 | + if( sqlite3_step(pSel)==SQLITE_ROW ){ |
| 240982 | + i64 val = sqlite3_column_int64(pSel, 0); |
| 240983 | + iPg = (int)(val>>1); |
| 240984 | + bDlidx = (val & 0x0001); |
| 240985 | + } |
| 240986 | + p->rc = sqlite3_reset(pSel); |
| 240987 | + sqlite3_bind_null(pSel, 2); |
| 240988 | + if( p->rc ) return; |
| 240989 | + } |
| 240990 | + |
| 240991 | + memset(pIter, 0, sizeof(*pIter)); |
| 240992 | + pIter->pSeg = pSeg; |
| 240993 | + pIter->flags |= FTS5_SEGITER_ONETERM; |
| 240994 | + if( iPg>=0 ){ |
| 240995 | + pIter->iLeafPgno = iPg - 1; |
| 240996 | + fts5SegIterNextPage(p, pIter); |
| 240997 | + fts5SegIterSetNext(p, pIter); |
| 240998 | + } |
| 240999 | + if( pIter->pLeaf ){ |
| 241000 | + const u8 *a = pIter->pLeaf->p; |
| 241001 | + int iTermOff = 0; |
| 241002 | + |
| 241003 | + pIter->iPgidxOff = pIter->pLeaf->szLeaf; |
| 241004 | + pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff); |
| 241005 | + pIter->iLeafOffset = iTermOff; |
| 241006 | + fts5SegIterLoadTerm(p, pIter, 0); |
| 241007 | + fts5SegIterLoadNPos(p, pIter); |
| 241008 | + if( bDlidx ) fts5SegIterLoadDlidx(p, pIter); |
| 241009 | + |
| 241010 | + assert( p->rc!=SQLITE_OK || |
| 241011 | + fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0 |
| 241012 | + ); |
| 241013 | + } |
| 241014 | +} |
| 241015 | + |
| 239060 | 241016 | /* |
| 239061 | 241017 | ** Initialize the object pIter to point to term pTerm/nTerm within the |
| 239062 | 241018 | ** in-memory hash table. If there is no such term in the hash-table, the |
| 239063 | 241019 | ** iterator is set to EOF. |
| 239064 | 241020 | ** |
| | @@ -239081,12 +241037,11 @@ |
| 239081 | 241037 | |
| 239082 | 241038 | if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ |
| 239083 | 241039 | const u8 *pList = 0; |
| 239084 | 241040 | |
| 239085 | 241041 | p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); |
| 239086 | | - sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); |
| 239087 | | - n = (z ? (int)strlen((const char*)z) : 0); |
| 241042 | + sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList); |
| 239088 | 241043 | if( pList ){ |
| 239089 | 241044 | pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); |
| 239090 | 241045 | if( pLeaf ){ |
| 239091 | 241046 | pLeaf->p = (u8*)pList; |
| 239092 | 241047 | } |
| | @@ -239140,19 +241095,36 @@ |
| 239140 | 241095 | fts5DataRelease(ap[ii]); |
| 239141 | 241096 | } |
| 239142 | 241097 | sqlite3_free(ap); |
| 239143 | 241098 | } |
| 239144 | 241099 | } |
| 241100 | + |
| 241101 | +/* |
| 241102 | +** Decrement the ref-count of the object passed as the only argument. If it |
| 241103 | +** reaches 0, free it and its contents. |
| 241104 | +*/ |
| 241105 | +static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){ |
| 241106 | + if( p ){ |
| 241107 | + p->nRef--; |
| 241108 | + if( p->nRef<=0 ){ |
| 241109 | + int ii; |
| 241110 | + for(ii=0; ii<p->nTombstone; ii++){ |
| 241111 | + fts5DataRelease(p->apTombstone[ii]); |
| 241112 | + } |
| 241113 | + sqlite3_free(p); |
| 241114 | + } |
| 241115 | + } |
| 241116 | +} |
| 239145 | 241117 | |
| 239146 | 241118 | /* |
| 239147 | 241119 | ** Zero the iterator passed as the only argument. |
| 239148 | 241120 | */ |
| 239149 | 241121 | static void fts5SegIterClear(Fts5SegIter *pIter){ |
| 239150 | 241122 | fts5BufferFree(&pIter->term); |
| 239151 | 241123 | fts5DataRelease(pIter->pLeaf); |
| 239152 | 241124 | fts5DataRelease(pIter->pNextLeaf); |
| 239153 | | - fts5IndexFreeArray(pIter->apTombstone, pIter->nTombstone); |
| 241125 | + fts5TombstoneArrayDelete(pIter->pTombArray); |
| 239154 | 241126 | fts5DlidxIterFree(pIter->pDlidx); |
| 239155 | 241127 | sqlite3_free(pIter->aRowidOffset); |
| 239156 | 241128 | memset(pIter, 0, sizeof(Fts5SegIter)); |
| 239157 | 241129 | } |
| 239158 | 241130 | |
| | @@ -239393,11 +241365,10 @@ |
| 239393 | 241365 | if( bRev!=0 && pIter->iRowid<=iMatch ) break; |
| 239394 | 241366 | bMove = 1; |
| 239395 | 241367 | }while( p->rc==SQLITE_OK ); |
| 239396 | 241368 | } |
| 239397 | 241369 | |
| 239398 | | - |
| 239399 | 241370 | /* |
| 239400 | 241371 | ** Free the iterator object passed as the second argument. |
| 239401 | 241372 | */ |
| 239402 | 241373 | static void fts5MultiIterFree(Fts5Iter *pIter){ |
| 239403 | 241374 | if( pIter ){ |
| | @@ -239538,28 +241509,29 @@ |
| 239538 | 241509 | ** if there is no tombstone or if the iterator is already at EOF. |
| 239539 | 241510 | */ |
| 239540 | 241511 | static int fts5MultiIterIsDeleted(Fts5Iter *pIter){ |
| 239541 | 241512 | int iFirst = pIter->aFirst[1].iFirst; |
| 239542 | 241513 | Fts5SegIter *pSeg = &pIter->aSeg[iFirst]; |
| 241514 | + Fts5TombstoneArray *pArray = pSeg->pTombArray; |
| 239543 | 241515 | |
| 239544 | | - if( pSeg->pLeaf && pSeg->nTombstone ){ |
| 241516 | + if( pSeg->pLeaf && pArray ){ |
| 239545 | 241517 | /* Figure out which page the rowid might be present on. */ |
| 239546 | | - int iPg = ((u64)pSeg->iRowid) % pSeg->nTombstone; |
| 241518 | + int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone; |
| 239547 | 241519 | assert( iPg>=0 ); |
| 239548 | 241520 | |
| 239549 | 241521 | /* If tombstone hash page iPg has not yet been loaded from the |
| 239550 | 241522 | ** database, load it now. */ |
| 239551 | | - if( pSeg->apTombstone[iPg]==0 ){ |
| 239552 | | - pSeg->apTombstone[iPg] = fts5DataRead(pIter->pIndex, |
| 241523 | + if( pArray->apTombstone[iPg]==0 ){ |
| 241524 | + pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex, |
| 239553 | 241525 | FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg) |
| 239554 | 241526 | ); |
| 239555 | | - if( pSeg->apTombstone[iPg]==0 ) return 0; |
| 241527 | + if( pArray->apTombstone[iPg]==0 ) return 0; |
| 239556 | 241528 | } |
| 239557 | 241529 | |
| 239558 | 241530 | return fts5IndexTombstoneQuery( |
| 239559 | | - pSeg->apTombstone[iPg], |
| 239560 | | - pSeg->nTombstone, |
| 241531 | + pArray->apTombstone[iPg], |
| 241532 | + pArray->nTombstone, |
| 239561 | 241533 | pSeg->iRowid |
| 239562 | 241534 | ); |
| 239563 | 241535 | } |
| 239564 | 241536 | |
| 239565 | 241537 | return 0; |
| | @@ -240094,10 +242066,36 @@ |
| 240094 | 242066 | } |
| 240095 | 242067 | } |
| 240096 | 242068 | } |
| 240097 | 242069 | } |
| 240098 | 242070 | |
| 242071 | +/* |
| 242072 | +** All the component segment-iterators of pIter have been set up. This |
| 242073 | +** functions finishes setup for iterator pIter itself. |
| 242074 | +*/ |
| 242075 | +static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){ |
| 242076 | + int iIter; |
| 242077 | + for(iIter=pIter->nSeg-1; iIter>0; iIter--){ |
| 242078 | + int iEq; |
| 242079 | + if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){ |
| 242080 | + Fts5SegIter *pSeg = &pIter->aSeg[iEq]; |
| 242081 | + if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); |
| 242082 | + fts5MultiIterAdvanced(p, pIter, iEq, iIter); |
| 242083 | + } |
| 242084 | + } |
| 242085 | + fts5MultiIterSetEof(pIter); |
| 242086 | + fts5AssertMultiIterSetup(p, pIter); |
| 242087 | + |
| 242088 | + if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter)) |
| 242089 | + || fts5MultiIterIsDeleted(pIter) |
| 242090 | + ){ |
| 242091 | + fts5MultiIterNext(p, pIter, 0, 0); |
| 242092 | + }else if( pIter->base.bEof==0 ){ |
| 242093 | + Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst]; |
| 242094 | + pIter->xSetOutputs(pIter, pSeg); |
| 242095 | + } |
| 242096 | +} |
| 240099 | 242097 | |
| 240100 | 242098 | /* |
| 240101 | 242099 | ** Allocate a new Fts5Iter object. |
| 240102 | 242100 | ** |
| 240103 | 242101 | ** The new object will be used to iterate through data in structure pStruct. |
| | @@ -240175,35 +242173,16 @@ |
| 240175 | 242173 | } |
| 240176 | 242174 | } |
| 240177 | 242175 | assert( iIter==nSeg ); |
| 240178 | 242176 | } |
| 240179 | 242177 | |
| 240180 | | - /* If the above was successful, each component iterators now points |
| 242178 | + /* If the above was successful, each component iterator now points |
| 240181 | 242179 | ** to the first entry in its segment. In this case initialize the |
| 240182 | 242180 | ** aFirst[] array. Or, if an error has occurred, free the iterator |
| 240183 | 242181 | ** object and set the output variable to NULL. */ |
| 240184 | 242182 | if( p->rc==SQLITE_OK ){ |
| 240185 | | - for(iIter=pNew->nSeg-1; iIter>0; iIter--){ |
| 240186 | | - int iEq; |
| 240187 | | - if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){ |
| 240188 | | - Fts5SegIter *pSeg = &pNew->aSeg[iEq]; |
| 240189 | | - if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0); |
| 240190 | | - fts5MultiIterAdvanced(p, pNew, iEq, iIter); |
| 240191 | | - } |
| 240192 | | - } |
| 240193 | | - fts5MultiIterSetEof(pNew); |
| 240194 | | - fts5AssertMultiIterSetup(p, pNew); |
| 240195 | | - |
| 240196 | | - if( (pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew)) |
| 240197 | | - || fts5MultiIterIsDeleted(pNew) |
| 240198 | | - ){ |
| 240199 | | - fts5MultiIterNext(p, pNew, 0, 0); |
| 240200 | | - }else if( pNew->base.bEof==0 ){ |
| 240201 | | - Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst]; |
| 240202 | | - pNew->xSetOutputs(pNew, pSeg); |
| 240203 | | - } |
| 240204 | | - |
| 242183 | + fts5MultiIterFinishSetup(p, pNew); |
| 240205 | 242184 | }else{ |
| 240206 | 242185 | fts5MultiIterFree(pNew); |
| 240207 | 242186 | *ppOut = 0; |
| 240208 | 242187 | } |
| 240209 | 242188 | |
| | @@ -240224,11 +242203,10 @@ |
| 240224 | 242203 | ){ |
| 240225 | 242204 | Fts5Iter *pNew; |
| 240226 | 242205 | pNew = fts5MultiIterAlloc(p, 2); |
| 240227 | 242206 | if( pNew ){ |
| 240228 | 242207 | Fts5SegIter *pIter = &pNew->aSeg[1]; |
| 240229 | | - |
| 240230 | 242208 | pIter->flags = FTS5_SEGITER_ONETERM; |
| 240231 | 242209 | if( pData->szLeaf>0 ){ |
| 240232 | 242210 | pIter->pLeaf = pData; |
| 240233 | 242211 | pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid); |
| 240234 | 242212 | pIter->iEndofDoclist = pData->nn; |
| | @@ -240372,10 +242350,11 @@ |
| 240372 | 242350 | assert( p->pHash || p->nPendingData==0 ); |
| 240373 | 242351 | if( p->pHash ){ |
| 240374 | 242352 | sqlite3Fts5HashClear(p->pHash); |
| 240375 | 242353 | p->nPendingData = 0; |
| 240376 | 242354 | p->nPendingRow = 0; |
| 242355 | + p->flushRc = SQLITE_OK; |
| 240377 | 242356 | } |
| 240378 | 242357 | p->nContentlessDelete = 0; |
| 240379 | 242358 | } |
| 240380 | 242359 | |
| 240381 | 242360 | /* |
| | @@ -240587,11 +242566,11 @@ |
| 240587 | 242566 | }else{ |
| 240588 | 242567 | bDone = 1; |
| 240589 | 242568 | } |
| 240590 | 242569 | |
| 240591 | 242570 | if( pDlidx->bPrevValid ){ |
| 240592 | | - iVal = iRowid - pDlidx->iPrev; |
| 242571 | + iVal = (u64)iRowid - (u64)pDlidx->iPrev; |
| 240593 | 242572 | }else{ |
| 240594 | 242573 | i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno); |
| 240595 | 242574 | assert( pDlidx->buf.n==0 ); |
| 240596 | 242575 | sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone); |
| 240597 | 242576 | sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno); |
| | @@ -241710,14 +243689,14 @@ |
| 241710 | 243689 | */ |
| 241711 | 243690 | static void fts5FlushSecureDelete( |
| 241712 | 243691 | Fts5Index *p, |
| 241713 | 243692 | Fts5Structure *pStruct, |
| 241714 | 243693 | const char *zTerm, |
| 243694 | + int nTerm, |
| 241715 | 243695 | i64 iRowid |
| 241716 | 243696 | ){ |
| 241717 | 243697 | const int f = FTS5INDEX_QUERY_SKIPHASH; |
| 241718 | | - int nTerm = (int)strlen(zTerm); |
| 241719 | 243698 | Fts5Iter *pIter = 0; /* Used to find term instance */ |
| 241720 | 243699 | |
| 241721 | 243700 | fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter); |
| 241722 | 243701 | if( fts5MultiIterEof(p, pIter)==0 ){ |
| 241723 | 243702 | i64 iThis = fts5MultiIterRowid(pIter); |
| | @@ -241787,12 +243766,11 @@ |
| 241787 | 243766 | int nTerm; /* Size of zTerm in bytes */ |
| 241788 | 243767 | const u8 *pDoclist; /* Pointer to doclist for this term */ |
| 241789 | 243768 | int nDoclist; /* Size of doclist in bytes */ |
| 241790 | 243769 | |
| 241791 | 243770 | /* Get the term and doclist for this entry. */ |
| 241792 | | - sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist); |
| 241793 | | - nTerm = (int)strlen(zTerm); |
| 243771 | + sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist); |
| 241794 | 243772 | if( bSecureDelete==0 ){ |
| 241795 | 243773 | fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm); |
| 241796 | 243774 | if( p->rc!=SQLITE_OK ) break; |
| 241797 | 243775 | assert( writer.bFirstRowidInPage==0 ); |
| 241798 | 243776 | } |
| | @@ -241818,21 +243796,21 @@ |
| 241818 | 243796 | ** in fact a delete, then edit the existing segments directly |
| 241819 | 243797 | ** using fts5FlushSecureDelete(). */ |
| 241820 | 243798 | if( bSecureDelete ){ |
| 241821 | 243799 | if( eDetail==FTS5_DETAIL_NONE ){ |
| 241822 | 243800 | if( iOff<nDoclist && pDoclist[iOff]==0x00 ){ |
| 241823 | | - fts5FlushSecureDelete(p, pStruct, zTerm, iRowid); |
| 243801 | + fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid); |
| 241824 | 243802 | iOff++; |
| 241825 | 243803 | if( iOff<nDoclist && pDoclist[iOff]==0x00 ){ |
| 241826 | 243804 | iOff++; |
| 241827 | 243805 | nDoclist = 0; |
| 241828 | 243806 | }else{ |
| 241829 | 243807 | continue; |
| 241830 | 243808 | } |
| 241831 | 243809 | } |
| 241832 | 243810 | }else if( (pDoclist[iOff] & 0x01) ){ |
| 241833 | | - fts5FlushSecureDelete(p, pStruct, zTerm, iRowid); |
| 243811 | + fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid); |
| 241834 | 243812 | if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){ |
| 241835 | 243813 | iOff++; |
| 241836 | 243814 | continue; |
| 241837 | 243815 | } |
| 241838 | 243816 | } |
| | @@ -241954,18 +243932,24 @@ |
| 241954 | 243932 | /* |
| 241955 | 243933 | ** Flush any data stored in the in-memory hash tables to the database. |
| 241956 | 243934 | */ |
| 241957 | 243935 | static void fts5IndexFlush(Fts5Index *p){ |
| 241958 | 243936 | /* Unless it is empty, flush the hash table to disk */ |
| 243937 | + if( p->flushRc ){ |
| 243938 | + p->rc = p->flushRc; |
| 243939 | + return; |
| 243940 | + } |
| 241959 | 243941 | if( p->nPendingData || p->nContentlessDelete ){ |
| 241960 | 243942 | assert( p->pHash ); |
| 241961 | 243943 | fts5FlushOneHash(p); |
| 241962 | 243944 | if( p->rc==SQLITE_OK ){ |
| 241963 | 243945 | sqlite3Fts5HashClear(p->pHash); |
| 241964 | 243946 | p->nPendingData = 0; |
| 241965 | 243947 | p->nPendingRow = 0; |
| 241966 | 243948 | p->nContentlessDelete = 0; |
| 243949 | + }else if( p->nPendingData || p->nContentlessDelete ){ |
| 243950 | + p->flushRc = p->rc; |
| 241967 | 243951 | } |
| 241968 | 243952 | } |
| 241969 | 243953 | } |
| 241970 | 243954 | |
| 241971 | 243955 | static Fts5Structure *fts5IndexOptimizeStruct( |
| | @@ -242448,11 +244432,11 @@ |
| 242448 | 244432 | int bDesc, /* True for "ORDER BY rowid DESC" */ |
| 242449 | 244433 | int iIdx, /* Index to scan for data */ |
| 242450 | 244434 | u8 *pToken, /* Buffer containing prefix to match */ |
| 242451 | 244435 | int nToken, /* Size of buffer pToken in bytes */ |
| 242452 | 244436 | Fts5Colset *pColset, /* Restrict matches to these columns */ |
| 242453 | | - Fts5Iter **ppIter /* OUT: New iterator */ |
| 244437 | + Fts5Iter **ppIter /* OUT: New iterator */ |
| 242454 | 244438 | ){ |
| 242455 | 244439 | Fts5Structure *pStruct; |
| 242456 | 244440 | Fts5Buffer *aBuf; |
| 242457 | 244441 | int nBuf = 32; |
| 242458 | 244442 | int nMerge = 1; |
| | @@ -242469,12 +244453,13 @@ |
| 242469 | 244453 | xAppend = fts5AppendPoslist; |
| 242470 | 244454 | } |
| 242471 | 244455 | |
| 242472 | 244456 | aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf); |
| 242473 | 244457 | pStruct = fts5StructureRead(p); |
| 244458 | + assert( p->rc!=SQLITE_OK || (aBuf && pStruct) ); |
| 242474 | 244459 | |
| 242475 | | - if( aBuf && pStruct ){ |
| 244460 | + if( p->rc==SQLITE_OK ){ |
| 242476 | 244461 | const int flags = FTS5INDEX_QUERY_SCAN |
| 242477 | 244462 | | FTS5INDEX_QUERY_SKIPEMPTY |
| 242478 | 244463 | | FTS5INDEX_QUERY_NOOUTPUT; |
| 242479 | 244464 | int i; |
| 242480 | 244465 | i64 iLastRowid = 0; |
| | @@ -242482,10 +244467,16 @@ |
| 242482 | 244467 | Fts5Data *pData; |
| 242483 | 244468 | Fts5Buffer doclist; |
| 242484 | 244469 | int bNewTerm = 1; |
| 242485 | 244470 | |
| 242486 | 244471 | memset(&doclist, 0, sizeof(doclist)); |
| 244472 | + |
| 244473 | + /* If iIdx is non-zero, then it is the number of a prefix-index for |
| 244474 | + ** prefixes 1 character longer than the prefix being queried for. That |
| 244475 | + ** index contains all the doclists required, except for the one |
| 244476 | + ** corresponding to the prefix itself. That one is extracted from the |
| 244477 | + ** main term index here. */ |
| 242487 | 244478 | if( iIdx!=0 ){ |
| 242488 | 244479 | int dummy = 0; |
| 242489 | 244480 | const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT; |
| 242490 | 244481 | pToken[0] = FTS5_MAIN_PREFIX; |
| 242491 | 244482 | fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1); |
| | @@ -242505,10 +244496,11 @@ |
| 242505 | 244496 | } |
| 242506 | 244497 | |
| 242507 | 244498 | pToken[0] = FTS5_MAIN_PREFIX + iIdx; |
| 242508 | 244499 | fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1); |
| 242509 | 244500 | fts5IterSetOutputCb(&p->rc, p1); |
| 244501 | + |
| 242510 | 244502 | for( /* no-op */ ; |
| 242511 | 244503 | fts5MultiIterEof(p, p1)==0; |
| 242512 | 244504 | fts5MultiIterNext2(p, p1, &bNewTerm) |
| 242513 | 244505 | ){ |
| 242514 | 244506 | Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ]; |
| | @@ -242520,11 +244512,10 @@ |
| 242520 | 244512 | if( bNewTerm ){ |
| 242521 | 244513 | if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break; |
| 242522 | 244514 | } |
| 242523 | 244515 | |
| 242524 | 244516 | if( p1->base.nData==0 ) continue; |
| 242525 | | - |
| 242526 | 244517 | if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){ |
| 242527 | 244518 | for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ |
| 242528 | 244519 | int i1 = i*nMerge; |
| 242529 | 244520 | int iStore; |
| 242530 | 244521 | assert( i1+nMerge<=nBuf ); |
| | @@ -242559,11 +244550,11 @@ |
| 242559 | 244550 | fts5BufferFree(&aBuf[iFree]); |
| 242560 | 244551 | } |
| 242561 | 244552 | } |
| 242562 | 244553 | fts5MultiIterFree(p1); |
| 242563 | 244554 | |
| 242564 | | - pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); |
| 244555 | + pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING); |
| 242565 | 244556 | if( pData ){ |
| 242566 | 244557 | pData->p = (u8*)&pData[1]; |
| 242567 | 244558 | pData->nn = pData->szLeaf = doclist.n; |
| 242568 | 244559 | if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n); |
| 242569 | 244560 | fts5MultiIterNew2(p, pData, bDesc, ppIter); |
| | @@ -242702,10 +244693,11 @@ |
| 242702 | 244693 | sqlite3_finalize(p->pWriter); |
| 242703 | 244694 | sqlite3_finalize(p->pDeleter); |
| 242704 | 244695 | sqlite3_finalize(p->pIdxWriter); |
| 242705 | 244696 | sqlite3_finalize(p->pIdxDeleter); |
| 242706 | 244697 | sqlite3_finalize(p->pIdxSelect); |
| 244698 | + sqlite3_finalize(p->pIdxNextSelect); |
| 242707 | 244699 | sqlite3_finalize(p->pDataVersion); |
| 242708 | 244700 | sqlite3_finalize(p->pDeleteFromIdx); |
| 242709 | 244701 | sqlite3Fts5HashFree(p->pHash); |
| 242710 | 244702 | sqlite3_free(p->zDataTbl); |
| 242711 | 244703 | sqlite3_free(p); |
| | @@ -242796,10 +244788,458 @@ |
| 242796 | 244788 | } |
| 242797 | 244789 | } |
| 242798 | 244790 | |
| 242799 | 244791 | return rc; |
| 242800 | 244792 | } |
| 244793 | + |
| 244794 | +/* |
| 244795 | +** pToken points to a buffer of size nToken bytes containing a search |
| 244796 | +** term, including the index number at the start, used on a tokendata=1 |
| 244797 | +** table. This function returns true if the term in buffer pBuf matches |
| 244798 | +** token pToken/nToken. |
| 244799 | +*/ |
| 244800 | +static int fts5IsTokendataPrefix( |
| 244801 | + Fts5Buffer *pBuf, |
| 244802 | + const u8 *pToken, |
| 244803 | + int nToken |
| 244804 | +){ |
| 244805 | + return ( |
| 244806 | + pBuf->n>=nToken |
| 244807 | + && 0==memcmp(pBuf->p, pToken, nToken) |
| 244808 | + && (pBuf->n==nToken || pBuf->p[nToken]==0x00) |
| 244809 | + ); |
| 244810 | +} |
| 244811 | + |
| 244812 | +/* |
| 244813 | +** Ensure the segment-iterator passed as the only argument points to EOF. |
| 244814 | +*/ |
| 244815 | +static void fts5SegIterSetEOF(Fts5SegIter *pSeg){ |
| 244816 | + fts5DataRelease(pSeg->pLeaf); |
| 244817 | + pSeg->pLeaf = 0; |
| 244818 | +} |
| 244819 | + |
| 244820 | +/* |
| 244821 | +** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an |
| 244822 | +** array of these for each row it visits. Or, for an iterator used by an |
| 244823 | +** "ORDER BY rank" query, it accumulates an array of these for the entire |
| 244824 | +** query. |
| 244825 | +** |
| 244826 | +** Each instance in the array indicates the iterator (and therefore term) |
| 244827 | +** associated with position iPos of rowid iRowid. This is used by the |
| 244828 | +** xInstToken() API. |
| 244829 | +*/ |
| 244830 | +struct Fts5TokenDataMap { |
| 244831 | + i64 iRowid; /* Row this token is located in */ |
| 244832 | + i64 iPos; /* Position of token */ |
| 244833 | + int iIter; /* Iterator token was read from */ |
| 244834 | +}; |
| 244835 | + |
| 244836 | +/* |
| 244837 | +** An object used to supplement Fts5Iter for tokendata=1 iterators. |
| 244838 | +*/ |
| 244839 | +struct Fts5TokenDataIter { |
| 244840 | + int nIter; |
| 244841 | + int nIterAlloc; |
| 244842 | + |
| 244843 | + int nMap; |
| 244844 | + int nMapAlloc; |
| 244845 | + Fts5TokenDataMap *aMap; |
| 244846 | + |
| 244847 | + Fts5PoslistReader *aPoslistReader; |
| 244848 | + int *aPoslistToIter; |
| 244849 | + Fts5Iter *apIter[1]; |
| 244850 | +}; |
| 244851 | + |
| 244852 | +/* |
| 244853 | +** This function appends iterator pAppend to Fts5TokenDataIter pIn and |
| 244854 | +** returns the result. |
| 244855 | +*/ |
| 244856 | +static Fts5TokenDataIter *fts5AppendTokendataIter( |
| 244857 | + Fts5Index *p, /* Index object (for error code) */ |
| 244858 | + Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */ |
| 244859 | + Fts5Iter *pAppend /* Append this iterator */ |
| 244860 | +){ |
| 244861 | + Fts5TokenDataIter *pRet = pIn; |
| 244862 | + |
| 244863 | + if( p->rc==SQLITE_OK ){ |
| 244864 | + if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ |
| 244865 | + int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; |
| 244866 | + int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter); |
| 244867 | + Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); |
| 244868 | + |
| 244869 | + if( pNew==0 ){ |
| 244870 | + p->rc = SQLITE_NOMEM; |
| 244871 | + }else{ |
| 244872 | + if( pIn==0 ) memset(pNew, 0, nByte); |
| 244873 | + pRet = pNew; |
| 244874 | + pNew->nIterAlloc = nAlloc; |
| 244875 | + } |
| 244876 | + } |
| 244877 | + } |
| 244878 | + if( p->rc ){ |
| 244879 | + sqlite3Fts5IterClose((Fts5IndexIter*)pAppend); |
| 244880 | + }else{ |
| 244881 | + pRet->apIter[pRet->nIter++] = pAppend; |
| 244882 | + } |
| 244883 | + assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc ); |
| 244884 | + |
| 244885 | + return pRet; |
| 244886 | +} |
| 244887 | + |
| 244888 | +/* |
| 244889 | +** Delete an Fts5TokenDataIter structure and its contents. |
| 244890 | +*/ |
| 244891 | +static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){ |
| 244892 | + if( pSet ){ |
| 244893 | + int ii; |
| 244894 | + for(ii=0; ii<pSet->nIter; ii++){ |
| 244895 | + fts5MultiIterFree(pSet->apIter[ii]); |
| 244896 | + } |
| 244897 | + sqlite3_free(pSet->aPoslistReader); |
| 244898 | + sqlite3_free(pSet->aMap); |
| 244899 | + sqlite3_free(pSet); |
| 244900 | + } |
| 244901 | +} |
| 244902 | + |
| 244903 | +/* |
| 244904 | +** Append a mapping to the token-map belonging to object pT. |
| 244905 | +*/ |
| 244906 | +static void fts5TokendataIterAppendMap( |
| 244907 | + Fts5Index *p, |
| 244908 | + Fts5TokenDataIter *pT, |
| 244909 | + int iIter, |
| 244910 | + i64 iRowid, |
| 244911 | + i64 iPos |
| 244912 | +){ |
| 244913 | + if( p->rc==SQLITE_OK ){ |
| 244914 | + if( pT->nMap==pT->nMapAlloc ){ |
| 244915 | + int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; |
| 244916 | + int nByte = nNew * sizeof(Fts5TokenDataMap); |
| 244917 | + Fts5TokenDataMap *aNew; |
| 244918 | + |
| 244919 | + aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte); |
| 244920 | + if( aNew==0 ){ |
| 244921 | + p->rc = SQLITE_NOMEM; |
| 244922 | + return; |
| 244923 | + } |
| 244924 | + |
| 244925 | + pT->aMap = aNew; |
| 244926 | + pT->nMapAlloc = nNew; |
| 244927 | + } |
| 244928 | + |
| 244929 | + pT->aMap[pT->nMap].iRowid = iRowid; |
| 244930 | + pT->aMap[pT->nMap].iPos = iPos; |
| 244931 | + pT->aMap[pT->nMap].iIter = iIter; |
| 244932 | + pT->nMap++; |
| 244933 | + } |
| 244934 | +} |
| 244935 | + |
| 244936 | +/* |
| 244937 | +** The iterator passed as the only argument must be a tokendata=1 iterator |
| 244938 | +** (pIter->pTokenDataIter!=0). This function sets the iterator output |
| 244939 | +** variables (pIter->base.*) according to the contents of the current |
| 244940 | +** row. |
| 244941 | +*/ |
| 244942 | +static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ |
| 244943 | + int ii; |
| 244944 | + int nHit = 0; |
| 244945 | + i64 iRowid = SMALLEST_INT64; |
| 244946 | + int iMin = 0; |
| 244947 | + |
| 244948 | + Fts5TokenDataIter *pT = pIter->pTokenDataIter; |
| 244949 | + |
| 244950 | + pIter->base.nData = 0; |
| 244951 | + pIter->base.pData = 0; |
| 244952 | + |
| 244953 | + for(ii=0; ii<pT->nIter; ii++){ |
| 244954 | + Fts5Iter *p = pT->apIter[ii]; |
| 244955 | + if( p->base.bEof==0 ){ |
| 244956 | + if( nHit==0 || p->base.iRowid<iRowid ){ |
| 244957 | + iRowid = p->base.iRowid; |
| 244958 | + nHit = 1; |
| 244959 | + pIter->base.pData = p->base.pData; |
| 244960 | + pIter->base.nData = p->base.nData; |
| 244961 | + iMin = ii; |
| 244962 | + }else if( p->base.iRowid==iRowid ){ |
| 244963 | + nHit++; |
| 244964 | + } |
| 244965 | + } |
| 244966 | + } |
| 244967 | + |
| 244968 | + if( nHit==0 ){ |
| 244969 | + pIter->base.bEof = 1; |
| 244970 | + }else{ |
| 244971 | + int eDetail = pIter->pIndex->pConfig->eDetail; |
| 244972 | + pIter->base.bEof = 0; |
| 244973 | + pIter->base.iRowid = iRowid; |
| 244974 | + |
| 244975 | + if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){ |
| 244976 | + fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1); |
| 244977 | + }else |
| 244978 | + if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){ |
| 244979 | + int nReader = 0; |
| 244980 | + int nByte = 0; |
| 244981 | + i64 iPrev = 0; |
| 244982 | + |
| 244983 | + /* Allocate array of iterators if they are not already allocated. */ |
| 244984 | + if( pT->aPoslistReader==0 ){ |
| 244985 | + pT->aPoslistReader = (Fts5PoslistReader*)sqlite3Fts5MallocZero( |
| 244986 | + &pIter->pIndex->rc, |
| 244987 | + pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int)) |
| 244988 | + ); |
| 244989 | + if( pT->aPoslistReader==0 ) return; |
| 244990 | + pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter]; |
| 244991 | + } |
| 244992 | + |
| 244993 | + /* Populate an iterator for each poslist that will be merged */ |
| 244994 | + for(ii=0; ii<pT->nIter; ii++){ |
| 244995 | + Fts5Iter *p = pT->apIter[ii]; |
| 244996 | + if( iRowid==p->base.iRowid ){ |
| 244997 | + pT->aPoslistToIter[nReader] = ii; |
| 244998 | + sqlite3Fts5PoslistReaderInit( |
| 244999 | + p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++] |
| 245000 | + ); |
| 245001 | + nByte += p->base.nData; |
| 245002 | + } |
| 245003 | + } |
| 245004 | + |
| 245005 | + /* Ensure the output buffer is large enough */ |
| 245006 | + if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){ |
| 245007 | + return; |
| 245008 | + } |
| 245009 | + |
| 245010 | + /* Ensure the token-mapping is large enough */ |
| 245011 | + if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){ |
| 245012 | + int nNew = (pT->nMapAlloc + nByte) * 2; |
| 245013 | + Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc( |
| 245014 | + pT->aMap, nNew*sizeof(Fts5TokenDataMap) |
| 245015 | + ); |
| 245016 | + if( aNew==0 ){ |
| 245017 | + pIter->pIndex->rc = SQLITE_NOMEM; |
| 245018 | + return; |
| 245019 | + } |
| 245020 | + pT->aMap = aNew; |
| 245021 | + pT->nMapAlloc = nNew; |
| 245022 | + } |
| 245023 | + |
| 245024 | + pIter->poslist.n = 0; |
| 245025 | + |
| 245026 | + while( 1 ){ |
| 245027 | + i64 iMinPos = LARGEST_INT64; |
| 245028 | + |
| 245029 | + /* Find smallest position */ |
| 245030 | + iMin = 0; |
| 245031 | + for(ii=0; ii<nReader; ii++){ |
| 245032 | + Fts5PoslistReader *pReader = &pT->aPoslistReader[ii]; |
| 245033 | + if( pReader->bEof==0 ){ |
| 245034 | + if( pReader->iPos<iMinPos ){ |
| 245035 | + iMinPos = pReader->iPos; |
| 245036 | + iMin = ii; |
| 245037 | + } |
| 245038 | + } |
| 245039 | + } |
| 245040 | + |
| 245041 | + /* If all readers were at EOF, break out of the loop. */ |
| 245042 | + if( iMinPos==LARGEST_INT64 ) break; |
| 245043 | + |
| 245044 | + sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos); |
| 245045 | + sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]); |
| 245046 | + |
| 245047 | + if( eDetail==FTS5_DETAIL_FULL ){ |
| 245048 | + pT->aMap[pT->nMap].iPos = iMinPos; |
| 245049 | + pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin]; |
| 245050 | + pT->aMap[pT->nMap].iRowid = iRowid; |
| 245051 | + pT->nMap++; |
| 245052 | + } |
| 245053 | + } |
| 245054 | + |
| 245055 | + pIter->base.pData = pIter->poslist.p; |
| 245056 | + pIter->base.nData = pIter->poslist.n; |
| 245057 | + } |
| 245058 | + } |
| 245059 | +} |
| 245060 | + |
| 245061 | +/* |
| 245062 | +** The iterator passed as the only argument must be a tokendata=1 iterator |
| 245063 | +** (pIter->pTokenDataIter!=0). This function advances the iterator. If |
| 245064 | +** argument bFrom is false, then the iterator is advanced to the next |
| 245065 | +** entry. Or, if bFrom is true, it is advanced to the first entry with |
| 245066 | +** a rowid of iFrom or greater. |
| 245067 | +*/ |
| 245068 | +static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){ |
| 245069 | + int ii; |
| 245070 | + Fts5TokenDataIter *pT = pIter->pTokenDataIter; |
| 245071 | + |
| 245072 | + for(ii=0; ii<pT->nIter; ii++){ |
| 245073 | + Fts5Iter *p = pT->apIter[ii]; |
| 245074 | + if( p->base.bEof==0 |
| 245075 | + && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom)) |
| 245076 | + ){ |
| 245077 | + fts5MultiIterNext(p->pIndex, p, bFrom, iFrom); |
| 245078 | + while( bFrom && p->base.bEof==0 |
| 245079 | + && p->base.iRowid<iFrom |
| 245080 | + && p->pIndex->rc==SQLITE_OK |
| 245081 | + ){ |
| 245082 | + fts5MultiIterNext(p->pIndex, p, 0, 0); |
| 245083 | + } |
| 245084 | + } |
| 245085 | + } |
| 245086 | + |
| 245087 | + fts5IterSetOutputsTokendata(pIter); |
| 245088 | +} |
| 245089 | + |
| 245090 | +/* |
| 245091 | +** If the segment-iterator passed as the first argument is at EOF, then |
| 245092 | +** set pIter->term to a copy of buffer pTerm. |
| 245093 | +*/ |
| 245094 | +static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){ |
| 245095 | + if( pIter && pIter->aSeg[0].pLeaf==0 ){ |
| 245096 | + fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p); |
| 245097 | + } |
| 245098 | +} |
| 245099 | + |
| 245100 | +/* |
| 245101 | +** This function sets up an iterator to use for a non-prefix query on a |
| 245102 | +** tokendata=1 table. |
| 245103 | +*/ |
| 245104 | +static Fts5Iter *fts5SetupTokendataIter( |
| 245105 | + Fts5Index *p, /* FTS index to query */ |
| 245106 | + const u8 *pToken, /* Buffer containing query term */ |
| 245107 | + int nToken, /* Size of buffer pToken in bytes */ |
| 245108 | + Fts5Colset *pColset /* Colset to filter on */ |
| 245109 | +){ |
| 245110 | + Fts5Iter *pRet = 0; |
| 245111 | + Fts5TokenDataIter *pSet = 0; |
| 245112 | + Fts5Structure *pStruct = 0; |
| 245113 | + const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN; |
| 245114 | + |
| 245115 | + Fts5Buffer bSeek = {0, 0, 0}; |
| 245116 | + Fts5Buffer *pSmall = 0; |
| 245117 | + |
| 245118 | + fts5IndexFlush(p); |
| 245119 | + pStruct = fts5StructureRead(p); |
| 245120 | + |
| 245121 | + while( p->rc==SQLITE_OK ){ |
| 245122 | + Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0; |
| 245123 | + Fts5Iter *pNew = 0; |
| 245124 | + Fts5SegIter *pNewIter = 0; |
| 245125 | + Fts5SegIter *pPrevIter = 0; |
| 245126 | + |
| 245127 | + int iLvl, iSeg, ii; |
| 245128 | + |
| 245129 | + pNew = fts5MultiIterAlloc(p, pStruct->nSegment); |
| 245130 | + if( pSmall ){ |
| 245131 | + fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p); |
| 245132 | + fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0"); |
| 245133 | + }else{ |
| 245134 | + fts5BufferSet(&p->rc, &bSeek, nToken, pToken); |
| 245135 | + } |
| 245136 | + if( p->rc ){ |
| 245137 | + sqlite3Fts5IterClose((Fts5IndexIter*)pNew); |
| 245138 | + break; |
| 245139 | + } |
| 245140 | + |
| 245141 | + pNewIter = &pNew->aSeg[0]; |
| 245142 | + pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0); |
| 245143 | + for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){ |
| 245144 | + for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){ |
| 245145 | + Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg]; |
| 245146 | + int bDone = 0; |
| 245147 | + |
| 245148 | + if( pPrevIter ){ |
| 245149 | + if( fts5BufferCompare(pSmall, &pPrevIter->term) ){ |
| 245150 | + memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter)); |
| 245151 | + memset(pPrevIter, 0, sizeof(Fts5SegIter)); |
| 245152 | + bDone = 1; |
| 245153 | + }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){ |
| 245154 | + fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter); |
| 245155 | + bDone = 1; |
| 245156 | + } |
| 245157 | + } |
| 245158 | + |
| 245159 | + if( bDone==0 ){ |
| 245160 | + fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter); |
| 245161 | + } |
| 245162 | + |
| 245163 | + if( pPrevIter ){ |
| 245164 | + if( pPrevIter->pTombArray ){ |
| 245165 | + pNewIter->pTombArray = pPrevIter->pTombArray; |
| 245166 | + pNewIter->pTombArray->nRef++; |
| 245167 | + } |
| 245168 | + }else{ |
| 245169 | + fts5SegIterAllocTombstone(p, pNewIter); |
| 245170 | + } |
| 245171 | + |
| 245172 | + pNewIter++; |
| 245173 | + if( pPrevIter ) pPrevIter++; |
| 245174 | + if( p->rc ) break; |
| 245175 | + } |
| 245176 | + } |
| 245177 | + fts5TokendataSetTermIfEof(pPrev, pSmall); |
| 245178 | + |
| 245179 | + pNew->bSkipEmpty = 1; |
| 245180 | + pNew->pColset = pColset; |
| 245181 | + fts5IterSetOutputCb(&p->rc, pNew); |
| 245182 | + |
| 245183 | + /* Loop through all segments in the new iterator. Find the smallest |
| 245184 | + ** term that any segment-iterator points to. Iterator pNew will be |
| 245185 | + ** used for this term. Also, set any iterator that points to a term that |
| 245186 | + ** does not match pToken/nToken to point to EOF */ |
| 245187 | + pSmall = 0; |
| 245188 | + for(ii=0; ii<pNew->nSeg; ii++){ |
| 245189 | + Fts5SegIter *pII = &pNew->aSeg[ii]; |
| 245190 | + if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){ |
| 245191 | + fts5SegIterSetEOF(pII); |
| 245192 | + } |
| 245193 | + if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){ |
| 245194 | + pSmall = &pII->term; |
| 245195 | + } |
| 245196 | + } |
| 245197 | + |
| 245198 | + /* If pSmall is still NULL at this point, then the new iterator does |
| 245199 | + ** not point to any terms that match the query. So delete it and break |
| 245200 | + ** out of the loop - all required iterators have been collected. */ |
| 245201 | + if( pSmall==0 ){ |
| 245202 | + sqlite3Fts5IterClose((Fts5IndexIter*)pNew); |
| 245203 | + break; |
| 245204 | + } |
| 245205 | + |
| 245206 | + /* Append this iterator to the set and continue. */ |
| 245207 | + pSet = fts5AppendTokendataIter(p, pSet, pNew); |
| 245208 | + } |
| 245209 | + |
| 245210 | + if( p->rc==SQLITE_OK && pSet ){ |
| 245211 | + int ii; |
| 245212 | + for(ii=0; ii<pSet->nIter; ii++){ |
| 245213 | + Fts5Iter *pIter = pSet->apIter[ii]; |
| 245214 | + int iSeg; |
| 245215 | + for(iSeg=0; iSeg<pIter->nSeg; iSeg++){ |
| 245216 | + pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM; |
| 245217 | + } |
| 245218 | + fts5MultiIterFinishSetup(p, pIter); |
| 245219 | + } |
| 245220 | + } |
| 245221 | + |
| 245222 | + if( p->rc==SQLITE_OK ){ |
| 245223 | + pRet = fts5MultiIterAlloc(p, 0); |
| 245224 | + } |
| 245225 | + if( pRet ){ |
| 245226 | + pRet->pTokenDataIter = pSet; |
| 245227 | + if( pSet ){ |
| 245228 | + fts5IterSetOutputsTokendata(pRet); |
| 245229 | + }else{ |
| 245230 | + pRet->base.bEof = 1; |
| 245231 | + } |
| 245232 | + }else{ |
| 245233 | + fts5TokendataIterDelete(pSet); |
| 245234 | + } |
| 245235 | + |
| 245236 | + fts5StructureRelease(pStruct); |
| 245237 | + fts5BufferFree(&bSeek); |
| 245238 | + return pRet; |
| 245239 | +} |
| 245240 | + |
| 242801 | 245241 | |
| 242802 | 245242 | /* |
| 242803 | 245243 | ** Open a new iterator to iterate though all rowid that match the |
| 242804 | 245244 | ** specified token or token prefix. |
| 242805 | 245245 | */ |
| | @@ -242818,11 +245258,16 @@ |
| 242818 | 245258 | assert( (flags & FTS5INDEX_QUERY_SCAN)==0 || flags==FTS5INDEX_QUERY_SCAN ); |
| 242819 | 245259 | |
| 242820 | 245260 | if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){ |
| 242821 | 245261 | int iIdx = 0; /* Index to search */ |
| 242822 | 245262 | int iPrefixIdx = 0; /* +1 prefix index */ |
| 245263 | + int bTokendata = pConfig->bTokendata; |
| 242823 | 245264 | if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken); |
| 245265 | + |
| 245266 | + if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){ |
| 245267 | + bTokendata = 0; |
| 245268 | + } |
| 242824 | 245269 | |
| 242825 | 245270 | /* Figure out which index to search and set iIdx accordingly. If this |
| 242826 | 245271 | ** is a prefix query for which there is no prefix index, set iIdx to |
| 242827 | 245272 | ** greater than pConfig->nPrefix to indicate that the query will be |
| 242828 | 245273 | ** satisfied by scanning multiple terms in the main index. |
| | @@ -242845,11 +245290,14 @@ |
| 242845 | 245290 | if( nIdxChar==nChar ) break; |
| 242846 | 245291 | if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx; |
| 242847 | 245292 | } |
| 242848 | 245293 | } |
| 242849 | 245294 | |
| 242850 | | - if( iIdx<=pConfig->nPrefix ){ |
| 245295 | + if( bTokendata && iIdx==0 ){ |
| 245296 | + buf.p[0] = '0'; |
| 245297 | + pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset); |
| 245298 | + }else if( iIdx<=pConfig->nPrefix ){ |
| 242851 | 245299 | /* Straight index lookup */ |
| 242852 | 245300 | Fts5Structure *pStruct = fts5StructureRead(p); |
| 242853 | 245301 | buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx); |
| 242854 | 245302 | if( pStruct ){ |
| 242855 | 245303 | fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY, |
| | @@ -242892,11 +245340,15 @@ |
| 242892 | 245340 | ** Move to the next matching rowid. |
| 242893 | 245341 | */ |
| 242894 | 245342 | static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){ |
| 242895 | 245343 | Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 242896 | 245344 | assert( pIter->pIndex->rc==SQLITE_OK ); |
| 242897 | | - fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); |
| 245345 | + if( pIter->pTokenDataIter ){ |
| 245346 | + fts5TokendataIterNext(pIter, 0, 0); |
| 245347 | + }else{ |
| 245348 | + fts5MultiIterNext(pIter->pIndex, pIter, 0, 0); |
| 245349 | + } |
| 242898 | 245350 | return fts5IndexReturn(pIter->pIndex); |
| 242899 | 245351 | } |
| 242900 | 245352 | |
| 242901 | 245353 | /* |
| 242902 | 245354 | ** Move to the next matching term/rowid. Used by the fts5vocab module. |
| | @@ -242925,11 +245377,15 @@ |
| 242925 | 245377 | ** definition of "at or after" depends on whether this iterator iterates |
| 242926 | 245378 | ** in ascending or descending rowid order. |
| 242927 | 245379 | */ |
| 242928 | 245380 | static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){ |
| 242929 | 245381 | Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 242930 | | - fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); |
| 245382 | + if( pIter->pTokenDataIter ){ |
| 245383 | + fts5TokendataIterNext(pIter, 1, iMatch); |
| 245384 | + }else{ |
| 245385 | + fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch); |
| 245386 | + } |
| 242931 | 245387 | return fts5IndexReturn(pIter->pIndex); |
| 242932 | 245388 | } |
| 242933 | 245389 | |
| 242934 | 245390 | /* |
| 242935 | 245391 | ** Return the current term. |
| | @@ -242939,18 +245395,112 @@ |
| 242939 | 245395 | const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); |
| 242940 | 245396 | assert_nc( z || n<=1 ); |
| 242941 | 245397 | *pn = n-1; |
| 242942 | 245398 | return (z ? &z[1] : 0); |
| 242943 | 245399 | } |
| 245400 | + |
| 245401 | +/* |
| 245402 | +** This is used by xInstToken() to access the token at offset iOff, column |
| 245403 | +** iCol of row iRowid. The token is returned via output variables *ppOut |
| 245404 | +** and *pnOut. The iterator passed as the first argument must be a tokendata=1 |
| 245405 | +** iterator (pIter->pTokenDataIter!=0). |
| 245406 | +*/ |
| 245407 | +static int sqlite3Fts5IterToken( |
| 245408 | + Fts5IndexIter *pIndexIter, |
| 245409 | + i64 iRowid, |
| 245410 | + int iCol, |
| 245411 | + int iOff, |
| 245412 | + const char **ppOut, int *pnOut |
| 245413 | +){ |
| 245414 | + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 245415 | + Fts5TokenDataIter *pT = pIter->pTokenDataIter; |
| 245416 | + Fts5TokenDataMap *aMap = pT->aMap; |
| 245417 | + i64 iPos = (((i64)iCol)<<32) + iOff; |
| 245418 | + |
| 245419 | + int i1 = 0; |
| 245420 | + int i2 = pT->nMap; |
| 245421 | + int iTest = 0; |
| 245422 | + |
| 245423 | + while( i2>i1 ){ |
| 245424 | + iTest = (i1 + i2) / 2; |
| 245425 | + |
| 245426 | + if( aMap[iTest].iRowid<iRowid ){ |
| 245427 | + i1 = iTest+1; |
| 245428 | + }else if( aMap[iTest].iRowid>iRowid ){ |
| 245429 | + i2 = iTest; |
| 245430 | + }else{ |
| 245431 | + if( aMap[iTest].iPos<iPos ){ |
| 245432 | + if( aMap[iTest].iPos<0 ){ |
| 245433 | + break; |
| 245434 | + } |
| 245435 | + i1 = iTest+1; |
| 245436 | + }else if( aMap[iTest].iPos>iPos ){ |
| 245437 | + i2 = iTest; |
| 245438 | + }else{ |
| 245439 | + break; |
| 245440 | + } |
| 245441 | + } |
| 245442 | + } |
| 245443 | + |
| 245444 | + if( i2>i1 ){ |
| 245445 | + Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter]; |
| 245446 | + *ppOut = (const char*)pMap->aSeg[0].term.p+1; |
| 245447 | + *pnOut = pMap->aSeg[0].term.n-1; |
| 245448 | + } |
| 245449 | + |
| 245450 | + return SQLITE_OK; |
| 245451 | +} |
| 245452 | + |
| 245453 | +/* |
| 245454 | +** Clear any existing entries from the token-map associated with the |
| 245455 | +** iterator passed as the only argument. |
| 245456 | +*/ |
| 245457 | +static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){ |
| 245458 | + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 245459 | + if( pIter && pIter->pTokenDataIter ){ |
| 245460 | + pIter->pTokenDataIter->nMap = 0; |
| 245461 | + } |
| 245462 | +} |
| 245463 | + |
| 245464 | +/* |
| 245465 | +** Set a token-mapping for the iterator passed as the first argument. This |
| 245466 | +** is used in detail=column or detail=none mode when a token is requested |
| 245467 | +** using the xInstToken() API. In this case the caller tokenizers the |
| 245468 | +** current row and configures the token-mapping via multiple calls to this |
| 245469 | +** function. |
| 245470 | +*/ |
| 245471 | +static int sqlite3Fts5IndexIterWriteTokendata( |
| 245472 | + Fts5IndexIter *pIndexIter, |
| 245473 | + const char *pToken, int nToken, |
| 245474 | + i64 iRowid, int iCol, int iOff |
| 245475 | +){ |
| 245476 | + Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 245477 | + Fts5TokenDataIter *pT = pIter->pTokenDataIter; |
| 245478 | + Fts5Index *p = pIter->pIndex; |
| 245479 | + int ii; |
| 245480 | + |
| 245481 | + assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL ); |
| 245482 | + assert( pIter->pTokenDataIter ); |
| 245483 | + |
| 245484 | + for(ii=0; ii<pT->nIter; ii++){ |
| 245485 | + Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term; |
| 245486 | + if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break; |
| 245487 | + } |
| 245488 | + if( ii<pT->nIter ){ |
| 245489 | + fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff); |
| 245490 | + } |
| 245491 | + return fts5IndexReturn(p); |
| 245492 | +} |
| 242944 | 245493 | |
| 242945 | 245494 | /* |
| 242946 | 245495 | ** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery(). |
| 242947 | 245496 | */ |
| 242948 | 245497 | static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){ |
| 242949 | 245498 | if( pIndexIter ){ |
| 242950 | 245499 | Fts5Iter *pIter = (Fts5Iter*)pIndexIter; |
| 242951 | 245500 | Fts5Index *pIndex = pIter->pIndex; |
| 245501 | + fts5TokendataIterDelete(pIter->pTokenDataIter); |
| 242952 | 245502 | fts5MultiIterFree(pIter); |
| 242953 | 245503 | sqlite3Fts5IndexCloseReader(pIndex); |
| 242954 | 245504 | } |
| 242955 | 245505 | } |
| 242956 | 245506 | |
| | @@ -243454,11 +246004,13 @@ |
| 243454 | 246004 | u64 *pCksum /* IN/OUT: Checksum value */ |
| 243455 | 246005 | ){ |
| 243456 | 246006 | int eDetail = p->pConfig->eDetail; |
| 243457 | 246007 | u64 cksum = *pCksum; |
| 243458 | 246008 | Fts5IndexIter *pIter = 0; |
| 243459 | | - int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter); |
| 246009 | + int rc = sqlite3Fts5IndexQuery( |
| 246010 | + p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter |
| 246011 | + ); |
| 243460 | 246012 | |
| 243461 | 246013 | while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){ |
| 243462 | 246014 | i64 rowid = pIter->iRowid; |
| 243463 | 246015 | |
| 243464 | 246016 | if( eDetail==FTS5_DETAIL_NONE ){ |
| | @@ -244151,10 +246703,28 @@ |
| 244151 | 246703 | |
| 244152 | 246704 | sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); |
| 244153 | 246705 | } |
| 244154 | 246706 | } |
| 244155 | 246707 | #endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ |
| 246708 | + |
| 246709 | +#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) |
| 246710 | +static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){ |
| 246711 | + int ii; |
| 246712 | + fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1); |
| 246713 | + if( *pRc==SQLITE_OK ){ |
| 246714 | + for(ii=0; ii<pTerm->n; ii++){ |
| 246715 | + if( pTerm->p[ii]==0x00 ){ |
| 246716 | + pBuf->p[pBuf->n++] = '\\'; |
| 246717 | + pBuf->p[pBuf->n++] = '0'; |
| 246718 | + }else{ |
| 246719 | + pBuf->p[pBuf->n++] = pTerm->p[ii]; |
| 246720 | + } |
| 246721 | + } |
| 246722 | + pBuf->p[pBuf->n] = 0x00; |
| 246723 | + } |
| 246724 | +} |
| 246725 | +#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */ |
| 244156 | 246726 | |
| 244157 | 246727 | #if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG) |
| 244158 | 246728 | /* |
| 244159 | 246729 | ** The implementation of user-defined scalar function fts5_decode(). |
| 244160 | 246730 | */ |
| | @@ -244259,13 +246829,12 @@ |
| 244259 | 246829 | |
| 244260 | 246830 | /* Read the term data for the next term*/ |
| 244261 | 246831 | iOff += fts5GetVarint32(&a[iOff], nAppend); |
| 244262 | 246832 | term.n = nKeep; |
| 244263 | 246833 | fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]); |
| 244264 | | - sqlite3Fts5BufferAppendPrintf( |
| 244265 | | - &rc, &s, " term=%.*s", term.n, (const char*)term.p |
| 244266 | | - ); |
| 246834 | + sqlite3Fts5BufferAppendPrintf(&rc, &s, " term="); |
| 246835 | + fts5BufferAppendTerm(&rc, &s, &term); |
| 244267 | 246836 | iOff += nAppend; |
| 244268 | 246837 | |
| 244269 | 246838 | /* Figure out where the doclist for this term ends */ |
| 244270 | 246839 | if( iPgidxOff<n ){ |
| 244271 | 246840 | int nIncr; |
| | @@ -244369,13 +246938,12 @@ |
| 244369 | 246938 | break; |
| 244370 | 246939 | } |
| 244371 | 246940 | fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]); |
| 244372 | 246941 | iOff += nByte; |
| 244373 | 246942 | |
| 244374 | | - sqlite3Fts5BufferAppendPrintf( |
| 244375 | | - &rc, &s, " term=%.*s", term.n, (const char*)term.p |
| 244376 | | - ); |
| 246943 | + sqlite3Fts5BufferAppendPrintf(&rc, &s, " term="); |
| 246944 | + fts5BufferAppendTerm(&rc, &s, &term); |
| 244377 | 246945 | iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff); |
| 244378 | 246946 | } |
| 244379 | 246947 | |
| 244380 | 246948 | fts5BufferFree(&term); |
| 244381 | 246949 | } |
| | @@ -244846,11 +247414,11 @@ |
| 244846 | 247414 | Fts5Table p; /* Public class members from fts5Int.h */ |
| 244847 | 247415 | Fts5Storage *pStorage; /* Document store */ |
| 244848 | 247416 | Fts5Global *pGlobal; /* Global (connection wide) data */ |
| 244849 | 247417 | Fts5Cursor *pSortCsr; /* Sort data from this cursor */ |
| 244850 | 247418 | int iSavepoint; /* Successful xSavepoint()+1 */ |
| 244851 | | - int bInSavepoint; |
| 247419 | + |
| 244852 | 247420 | #ifdef SQLITE_DEBUG |
| 244853 | 247421 | struct Fts5TransactionState ts; |
| 244854 | 247422 | #endif |
| 244855 | 247423 | }; |
| 244856 | 247424 | |
| | @@ -245384,16 +247952,19 @@ |
| 245384 | 247952 | } |
| 245385 | 247953 | } |
| 245386 | 247954 | } |
| 245387 | 247955 | idxStr[iIdxStr] = '\0'; |
| 245388 | 247956 | |
| 245389 | | - /* Set idxFlags flags for the ORDER BY clause */ |
| 247957 | + /* Set idxFlags flags for the ORDER BY clause |
| 247958 | + ** |
| 247959 | + ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC". |
| 247960 | + */ |
| 245390 | 247961 | if( pInfo->nOrderBy==1 ){ |
| 245391 | 247962 | int iSort = pInfo->aOrderBy[0].iColumn; |
| 245392 | 247963 | if( iSort==(pConfig->nCol+1) && bSeenMatch ){ |
| 245393 | 247964 | idxFlags |= FTS5_BI_ORDER_RANK; |
| 245394 | | - }else if( iSort==-1 ){ |
| 247965 | + }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){ |
| 245395 | 247966 | idxFlags |= FTS5_BI_ORDER_ROWID; |
| 245396 | 247967 | } |
| 245397 | 247968 | if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){ |
| 245398 | 247969 | pInfo->orderByConsumed = 1; |
| 245399 | 247970 | if( pInfo->aOrderBy[0].desc ){ |
| | @@ -245640,10 +248211,20 @@ |
| 245640 | 248211 | |
| 245641 | 248212 | assert( (pCsr->ePlan<3)== |
| 245642 | 248213 | (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) |
| 245643 | 248214 | ); |
| 245644 | 248215 | assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) ); |
| 248216 | + |
| 248217 | + /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table, |
| 248218 | + ** clear any token mappings accumulated at the fts5_index.c level. In |
| 248219 | + ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH, |
| 248220 | + ** we need to retain the mappings for the entire query. */ |
| 248221 | + if( pCsr->ePlan==FTS5_PLAN_MATCH |
| 248222 | + && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata |
| 248223 | + ){ |
| 248224 | + sqlite3Fts5ExprClearTokens(pCsr->pExpr); |
| 248225 | + } |
| 245645 | 248226 | |
| 245646 | 248227 | if( pCsr->ePlan<3 ){ |
| 245647 | 248228 | int bSkip = 0; |
| 245648 | 248229 | if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc; |
| 245649 | 248230 | rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid); |
| | @@ -246791,16 +249372,10 @@ |
| 246791 | 249372 | if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 |
| 246792 | 249373 | || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) |
| 246793 | 249374 | ){ |
| 246794 | 249375 | if( iIdx<0 || iIdx>=pCsr->nInstCount ){ |
| 246795 | 249376 | rc = SQLITE_RANGE; |
| 246796 | | -#if 0 |
| 246797 | | - }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){ |
| 246798 | | - *piPhrase = pCsr->aInst[iIdx*3]; |
| 246799 | | - *piCol = pCsr->aInst[iIdx*3 + 2]; |
| 246800 | | - *piOff = -1; |
| 246801 | | -#endif |
| 246802 | 249377 | }else{ |
| 246803 | 249378 | *piPhrase = pCsr->aInst[iIdx*3]; |
| 246804 | 249379 | *piCol = pCsr->aInst[iIdx*3 + 1]; |
| 246805 | 249380 | *piOff = pCsr->aInst[iIdx*3 + 2]; |
| 246806 | 249381 | } |
| | @@ -247051,17 +249626,60 @@ |
| 247051 | 249626 | } |
| 247052 | 249627 | |
| 247053 | 249628 | return rc; |
| 247054 | 249629 | } |
| 247055 | 249630 | |
| 249631 | +/* |
| 249632 | +** xQueryToken() API implemenetation. |
| 249633 | +*/ |
| 249634 | +static int fts5ApiQueryToken( |
| 249635 | + Fts5Context* pCtx, |
| 249636 | + int iPhrase, |
| 249637 | + int iToken, |
| 249638 | + const char **ppOut, |
| 249639 | + int *pnOut |
| 249640 | +){ |
| 249641 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 249642 | + return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut); |
| 249643 | +} |
| 249644 | + |
| 249645 | +/* |
| 249646 | +** xInstToken() API implemenetation. |
| 249647 | +*/ |
| 249648 | +static int fts5ApiInstToken( |
| 249649 | + Fts5Context *pCtx, |
| 249650 | + int iIdx, |
| 249651 | + int iToken, |
| 249652 | + const char **ppOut, int *pnOut |
| 249653 | +){ |
| 249654 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 249655 | + int rc = SQLITE_OK; |
| 249656 | + if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 |
| 249657 | + || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) |
| 249658 | + ){ |
| 249659 | + if( iIdx<0 || iIdx>=pCsr->nInstCount ){ |
| 249660 | + rc = SQLITE_RANGE; |
| 249661 | + }else{ |
| 249662 | + int iPhrase = pCsr->aInst[iIdx*3]; |
| 249663 | + int iCol = pCsr->aInst[iIdx*3 + 1]; |
| 249664 | + int iOff = pCsr->aInst[iIdx*3 + 2]; |
| 249665 | + i64 iRowid = fts5CursorRowid(pCsr); |
| 249666 | + rc = sqlite3Fts5ExprInstToken( |
| 249667 | + pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut |
| 249668 | + ); |
| 249669 | + } |
| 249670 | + } |
| 249671 | + return rc; |
| 249672 | +} |
| 249673 | + |
| 247056 | 249674 | |
| 247057 | 249675 | static int fts5ApiQueryPhrase(Fts5Context*, int, void*, |
| 247058 | 249676 | int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) |
| 247059 | 249677 | ); |
| 247060 | 249678 | |
| 247061 | 249679 | static const Fts5ExtensionApi sFts5Api = { |
| 247062 | | - 2, /* iVersion */ |
| 249680 | + 3, /* iVersion */ |
| 247063 | 249681 | fts5ApiUserData, |
| 247064 | 249682 | fts5ApiColumnCount, |
| 247065 | 249683 | fts5ApiRowCount, |
| 247066 | 249684 | fts5ApiColumnTotalSize, |
| 247067 | 249685 | fts5ApiTokenize, |
| | @@ -247077,10 +249695,12 @@ |
| 247077 | 249695 | fts5ApiGetAuxdata, |
| 247078 | 249696 | fts5ApiPhraseFirst, |
| 247079 | 249697 | fts5ApiPhraseNext, |
| 247080 | 249698 | fts5ApiPhraseFirstColumn, |
| 247081 | 249699 | fts5ApiPhraseNextColumn, |
| 249700 | + fts5ApiQueryToken, |
| 249701 | + fts5ApiInstToken |
| 247082 | 249702 | }; |
| 247083 | 249703 | |
| 247084 | 249704 | /* |
| 247085 | 249705 | ** Implementation of API function xQueryPhrase(). |
| 247086 | 249706 | */ |
| | @@ -247343,13 +249963,11 @@ |
| 247343 | 249963 | sqlite3_vtab *pVtab, /* Virtual table handle */ |
| 247344 | 249964 | const char *zName /* New name of table */ |
| 247345 | 249965 | ){ |
| 247346 | 249966 | int rc; |
| 247347 | 249967 | Fts5FullTable *pTab = (Fts5FullTable*)pVtab; |
| 247348 | | - pTab->bInSavepoint = 1; |
| 247349 | 249968 | rc = sqlite3Fts5StorageRename(pTab->pStorage, zName); |
| 247350 | | - pTab->bInSavepoint = 0; |
| 247351 | 249969 | return rc; |
| 247352 | 249970 | } |
| 247353 | 249971 | |
| 247354 | 249972 | static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){ |
| 247355 | 249973 | fts5TripCursors((Fts5FullTable*)pTab); |
| | @@ -247362,30 +249980,16 @@ |
| 247362 | 249980 | ** Flush the contents of the pending-terms table to disk. |
| 247363 | 249981 | */ |
| 247364 | 249982 | static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 247365 | 249983 | Fts5FullTable *pTab = (Fts5FullTable*)pVtab; |
| 247366 | 249984 | int rc = SQLITE_OK; |
| 247367 | | - char *zSql = 0; |
| 249985 | + |
| 247368 | 249986 | fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); |
| 247369 | | - |
| 247370 | | - if( pTab->bInSavepoint==0 ){ |
| 247371 | | - zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')", |
| 247372 | | - pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName |
| 247373 | | - ); |
| 247374 | | - if( zSql ){ |
| 247375 | | - pTab->bInSavepoint = 1; |
| 247376 | | - rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0); |
| 247377 | | - pTab->bInSavepoint = 0; |
| 247378 | | - sqlite3_free(zSql); |
| 247379 | | - }else{ |
| 247380 | | - rc = SQLITE_NOMEM; |
| 247381 | | - } |
| 247382 | | - if( rc==SQLITE_OK ){ |
| 247383 | | - pTab->iSavepoint = iSavepoint+1; |
| 247384 | | - } |
| 247385 | | - } |
| 247386 | | - |
| 249987 | + rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab); |
| 249988 | + if( rc==SQLITE_OK ){ |
| 249989 | + pTab->iSavepoint = iSavepoint+1; |
| 249990 | + } |
| 247387 | 249991 | return rc; |
| 247388 | 249992 | } |
| 247389 | 249993 | |
| 247390 | 249994 | /* |
| 247391 | 249995 | ** The xRelease() method. |
| | @@ -247619,11 +250223,11 @@ |
| 247619 | 250223 | int nArg, /* Number of args */ |
| 247620 | 250224 | sqlite3_value **apUnused /* Function arguments */ |
| 247621 | 250225 | ){ |
| 247622 | 250226 | assert( nArg==0 ); |
| 247623 | 250227 | UNUSED_PARAM2(nArg, apUnused); |
| 247624 | | - sqlite3_result_text(pCtx, "fts5: 2023-11-24 11:41:44 ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f", -1, SQLITE_TRANSIENT); |
| 250228 | + sqlite3_result_text(pCtx, "fts5: 2023-12-14 16:34:47 27d4a89a5ff96b7b7fc5dc9650e1269f7c7edf91de9b9aafce40be9ecc8b95e9", -1, SQLITE_TRANSIENT); |
| 247625 | 250229 | } |
| 247626 | 250230 | |
| 247627 | 250231 | /* |
| 247628 | 250232 | ** Return true if zName is the extension on one of the shadow tables used |
| 247629 | 250233 | ** by this module. |
| | @@ -247642,11 +250246,11 @@ |
| 247642 | 250246 | /* |
| 247643 | 250247 | ** Run an integrity check on the FTS5 data structures. Return a string |
| 247644 | 250248 | ** if anything is found amiss. Return a NULL pointer if everything is |
| 247645 | 250249 | ** OK. |
| 247646 | 250250 | */ |
| 247647 | | -static int fts5Integrity( |
| 250251 | +static int fts5IntegrityMethod( |
| 247648 | 250252 | sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */ |
| 247649 | 250253 | const char *zSchema, /* Name of schema in which this table lives */ |
| 247650 | 250254 | const char *zTabname, /* Name of the table itself */ |
| 247651 | 250255 | int isQuick, /* True if this is a quick-check */ |
| 247652 | 250256 | char **pzErr /* Write error message here */ |
| | @@ -247700,11 +250304,11 @@ |
| 247700 | 250304 | /* xRename */ fts5RenameMethod, |
| 247701 | 250305 | /* xSavepoint */ fts5SavepointMethod, |
| 247702 | 250306 | /* xRelease */ fts5ReleaseMethod, |
| 247703 | 250307 | /* xRollbackTo */ fts5RollbackToMethod, |
| 247704 | 250308 | /* xShadowName */ fts5ShadowName, |
| 247705 | | - /* xIntegrity */ fts5Integrity |
| 250309 | + /* xIntegrity */ fts5IntegrityMethod |
| 247706 | 250310 | }; |
| 247707 | 250311 | |
| 247708 | 250312 | int rc; |
| 247709 | 250313 | Fts5Global *pGlobal = 0; |
| 247710 | 250314 | |
| | @@ -248466,11 +251070,11 @@ |
| 248466 | 251070 | if( rc==SQLITE_OK ){ |
| 248467 | 251071 | rc = fts5StorageLoadTotals(p, 1); |
| 248468 | 251072 | } |
| 248469 | 251073 | |
| 248470 | 251074 | if( rc==SQLITE_OK ){ |
| 248471 | | - rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); |
| 251075 | + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg); |
| 248472 | 251076 | } |
| 248473 | 251077 | |
| 248474 | 251078 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){ |
| 248475 | 251079 | i64 iRowid = sqlite3_column_int64(pScan, 0); |
| 248476 | 251080 | |
| | @@ -249252,10 +251856,16 @@ |
| 249252 | 251856 | *zOut++ = 0x80 + (unsigned char)(c & 0x3F); \ |
| 249253 | 251857 | } \ |
| 249254 | 251858 | } |
| 249255 | 251859 | |
| 249256 | 251860 | #endif /* ifndef SQLITE_AMALGAMATION */ |
| 251861 | + |
| 251862 | +#define FTS5_SKIP_UTF8(zIn) { \ |
| 251863 | + if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \ |
| 251864 | + while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \ |
| 251865 | + } \ |
| 251866 | +} |
| 249257 | 251867 | |
| 249258 | 251868 | typedef struct Unicode61Tokenizer Unicode61Tokenizer; |
| 249259 | 251869 | struct Unicode61Tokenizer { |
| 249260 | 251870 | unsigned char aTokenChar[128]; /* ASCII range token characters */ |
| 249261 | 251871 | char *aFold; /* Buffer to fold text into */ |
| | @@ -250288,10 +252898,11 @@ |
| 250288 | 252898 | ** Start of trigram implementation. |
| 250289 | 252899 | */ |
| 250290 | 252900 | typedef struct TrigramTokenizer TrigramTokenizer; |
| 250291 | 252901 | struct TrigramTokenizer { |
| 250292 | 252902 | int bFold; /* True to fold to lower-case */ |
| 252903 | + int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */ |
| 250293 | 252904 | }; |
| 250294 | 252905 | |
| 250295 | 252906 | /* |
| 250296 | 252907 | ** Free a trigram tokenizer. |
| 250297 | 252908 | */ |
| | @@ -250314,22 +252925,34 @@ |
| 250314 | 252925 | if( pNew==0 ){ |
| 250315 | 252926 | rc = SQLITE_NOMEM; |
| 250316 | 252927 | }else{ |
| 250317 | 252928 | int i; |
| 250318 | 252929 | pNew->bFold = 1; |
| 252930 | + pNew->iFoldParam = 0; |
| 250319 | 252931 | for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ |
| 250320 | 252932 | const char *zArg = azArg[i+1]; |
| 250321 | 252933 | if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){ |
| 250322 | 252934 | if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){ |
| 250323 | 252935 | rc = SQLITE_ERROR; |
| 250324 | 252936 | }else{ |
| 250325 | 252937 | pNew->bFold = (zArg[0]=='0'); |
| 250326 | 252938 | } |
| 252939 | + }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ |
| 252940 | + if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ |
| 252941 | + rc = SQLITE_ERROR; |
| 252942 | + }else{ |
| 252943 | + pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; |
| 252944 | + } |
| 250327 | 252945 | }else{ |
| 250328 | 252946 | rc = SQLITE_ERROR; |
| 250329 | 252947 | } |
| 250330 | 252948 | } |
| 252949 | + |
| 252950 | + if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ |
| 252951 | + rc = SQLITE_ERROR; |
| 252952 | + } |
| 252953 | + |
| 250331 | 252954 | if( rc!=SQLITE_OK ){ |
| 250332 | 252955 | fts5TriDelete((Fts5Tokenizer*)pNew); |
| 250333 | 252956 | pNew = 0; |
| 250334 | 252957 | } |
| 250335 | 252958 | } |
| | @@ -250348,44 +252971,66 @@ |
| 250348 | 252971 | int (*xToken)(void*, int, const char*, int, int, int) |
| 250349 | 252972 | ){ |
| 250350 | 252973 | TrigramTokenizer *p = (TrigramTokenizer*)pTok; |
| 250351 | 252974 | int rc = SQLITE_OK; |
| 250352 | 252975 | char aBuf[32]; |
| 252976 | + char *zOut = aBuf; |
| 252977 | + int ii; |
| 250353 | 252978 | const unsigned char *zIn = (const unsigned char*)pText; |
| 250354 | 252979 | const unsigned char *zEof = &zIn[nText]; |
| 250355 | 252980 | u32 iCode; |
| 252981 | + int aStart[3]; /* Input offset of each character in aBuf[] */ |
| 250356 | 252982 | |
| 250357 | 252983 | UNUSED_PARAM(unusedFlags); |
| 250358 | | - while( 1 ){ |
| 250359 | | - char *zOut = aBuf; |
| 250360 | | - int iStart = zIn - (const unsigned char*)pText; |
| 250361 | | - const unsigned char *zNext; |
| 250362 | | - |
| 250363 | | - READ_UTF8(zIn, zEof, iCode); |
| 250364 | | - if( iCode==0 ) break; |
| 250365 | | - zNext = zIn; |
| 250366 | | - if( zIn<zEof ){ |
| 250367 | | - if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); |
| 250368 | | - WRITE_UTF8(zOut, iCode); |
| 250369 | | - READ_UTF8(zIn, zEof, iCode); |
| 250370 | | - if( iCode==0 ) break; |
| 250371 | | - }else{ |
| 250372 | | - break; |
| 250373 | | - } |
| 250374 | | - if( zIn<zEof ){ |
| 250375 | | - if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); |
| 250376 | | - WRITE_UTF8(zOut, iCode); |
| 250377 | | - READ_UTF8(zIn, zEof, iCode); |
| 250378 | | - if( iCode==0 ) break; |
| 250379 | | - if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); |
| 250380 | | - WRITE_UTF8(zOut, iCode); |
| 250381 | | - }else{ |
| 250382 | | - break; |
| 250383 | | - } |
| 250384 | | - rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf); |
| 250385 | | - if( rc!=SQLITE_OK ) break; |
| 250386 | | - zIn = zNext; |
| 252984 | + |
| 252985 | + /* Populate aBuf[] with the characters for the first trigram. */ |
| 252986 | + for(ii=0; ii<3; ii++){ |
| 252987 | + do { |
| 252988 | + aStart[ii] = zIn - (const unsigned char*)pText; |
| 252989 | + READ_UTF8(zIn, zEof, iCode); |
| 252990 | + if( iCode==0 ) return SQLITE_OK; |
| 252991 | + if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); |
| 252992 | + }while( iCode==0 ); |
| 252993 | + WRITE_UTF8(zOut, iCode); |
| 252994 | + } |
| 252995 | + |
| 252996 | + /* At the start of each iteration of this loop: |
| 252997 | + ** |
| 252998 | + ** aBuf: Contains 3 characters. The 3 characters of the next trigram. |
| 252999 | + ** zOut: Points to the byte following the last character in aBuf. |
| 253000 | + ** aStart[3]: Contains the byte offset in the input text corresponding |
| 253001 | + ** to the start of each of the three characters in the buffer. |
| 253002 | + */ |
| 253003 | + assert( zIn<=zEof ); |
| 253004 | + while( 1 ){ |
| 253005 | + int iNext; /* Start of character following current tri */ |
| 253006 | + const char *z1; |
| 253007 | + |
| 253008 | + /* Read characters from the input up until the first non-diacritic */ |
| 253009 | + do { |
| 253010 | + iNext = zIn - (const unsigned char*)pText; |
| 253011 | + READ_UTF8(zIn, zEof, iCode); |
| 253012 | + if( iCode==0 ) break; |
| 253013 | + if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam); |
| 253014 | + }while( iCode==0 ); |
| 253015 | + |
| 253016 | + /* Pass the current trigram back to fts5 */ |
| 253017 | + rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext); |
| 253018 | + if( iCode==0 || rc!=SQLITE_OK ) break; |
| 253019 | + |
| 253020 | + /* Remove the first character from buffer aBuf[]. Append the character |
| 253021 | + ** with codepoint iCode. */ |
| 253022 | + z1 = aBuf; |
| 253023 | + FTS5_SKIP_UTF8(z1); |
| 253024 | + memmove(aBuf, z1, zOut - z1); |
| 253025 | + zOut -= (z1 - aBuf); |
| 253026 | + WRITE_UTF8(zOut, iCode); |
| 253027 | + |
| 253028 | + /* Update the aStart[] array */ |
| 253029 | + aStart[0] = aStart[1]; |
| 253030 | + aStart[1] = aStart[2]; |
| 253031 | + aStart[2] = iNext; |
| 250387 | 253032 | } |
| 250388 | 253033 | |
| 250389 | 253034 | return rc; |
| 250390 | 253035 | } |
| 250391 | 253036 | |
| | @@ -250404,11 +253049,13 @@ |
| 250404 | 253049 | int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), |
| 250405 | 253050 | Fts5Tokenizer *pTok |
| 250406 | 253051 | ){ |
| 250407 | 253052 | if( xCreate==fts5TriCreate ){ |
| 250408 | 253053 | TrigramTokenizer *p = (TrigramTokenizer*)pTok; |
| 250409 | | - return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; |
| 253054 | + if( p->iFoldParam==0 ){ |
| 253055 | + return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; |
| 253056 | + } |
| 250410 | 253057 | } |
| 250411 | 253058 | return FTS5_PATTERN_NONE; |
| 250412 | 253059 | } |
| 250413 | 253060 | |
| 250414 | 253061 | /* |
| | @@ -252193,11 +254840,11 @@ |
| 252193 | 254840 | if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; |
| 252194 | 254841 | |
| 252195 | 254842 | if( pEq ){ |
| 252196 | 254843 | zTerm = (const char *)sqlite3_value_text(pEq); |
| 252197 | 254844 | nTerm = sqlite3_value_bytes(pEq); |
| 252198 | | - f = 0; |
| 254845 | + f = FTS5INDEX_QUERY_NOTOKENDATA; |
| 252199 | 254846 | }else{ |
| 252200 | 254847 | if( pGe ){ |
| 252201 | 254848 | zTerm = (const char *)sqlite3_value_text(pGe); |
| 252202 | 254849 | nTerm = sqlite3_value_bytes(pGe); |
| 252203 | 254850 | } |
| 252204 | 254851 | |