1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-09 14:21:03 +03:00

Improvements to comments and procedure names for clarity in the JSON

implementation.

FossilOrigin-Name: 9b620d813ef483f1277c1683c5e926a882f07f3b90804dea0c91b325ff8e45a4
This commit is contained in:
drh
2023-09-29 12:45:14 +00:00
parent ecce6022d5
commit ae5f55e227
3 changed files with 161 additions and 138 deletions

View File

@@ -1,5 +1,5 @@
C Describe\sthe\sJSONB\sencoding\sin\sa\sheader\scomment\sto\sthe\sjson.c\ssource\sfile. C Improvements\sto\scomments\sand\sprocedure\snames\sfor\sclarity\sin\sthe\sJSON\nimplementation.
D 2023-09-29T11:17:43.227 D 2023-09-29T12:45:14.794
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -670,7 +670,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c 6d2643118360760d589829d5a10d612a0270729ce11b303553502eae70c8f899 F src/json.c 92d7c2ea8db842cd6a7a7b664bf43d5ae75e097981f001a5ab3860bd222132ca
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0 F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40 F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40
@@ -2123,8 +2123,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1744bfc669346ff221f28d45fd978863e876a2d2f0b82bcf0e5ee6f0326900cc P 1c0cba3461d6111b3aeb77726880221f1240355f0b57e060febbdeb12fb688c0
R 88ae9ef60dd50edd212e3ca11b3078d3 R d73ce77d34a070de20c2504f2815e166
U drh U drh
Z 174eaa9aa981071dd243f3ac21aacaae Z 100adbc30a124e4f2d5cc09bea6ade0f
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
1c0cba3461d6111b3aeb77726880221f1240355f0b57e060febbdeb12fb688c0 9b620d813ef483f1277c1683c5e926a882f07f3b90804dea0c91b325ff8e45a4

View File

@@ -33,9 +33,8 @@
** for delimiters using persnickety syntax rules. JSONB seems to be about ** for delimiters using persnickety syntax rules. JSONB seems to be about
** 3x faster than text JSON as a result. JSONB is also tends to be slightly ** 3x faster than text JSON as a result. JSONB is also tends to be slightly
** smaller than text JSON, by 5% or 10%, but there are corner cases where ** smaller than text JSON, by 5% or 10%, but there are corner cases where
** JSONB can be slightly larger. Roughtly speaking, though, a JSONB blob ** JSONB can be slightly larger. So you are not far mistaken to say that
** and the equivalent RFC-8259 text string take up the same amount of space ** a JSONB blob is the same size as the equivalent RFC-8259 text.
** on disk.
** **
** **
** THE JSONB ENCODING: ** THE JSONB ENCODING:
@@ -55,9 +54,9 @@
** 5: FLOAT -- RFC-8259 floating point literal ** 5: FLOAT -- RFC-8259 floating point literal
** 6: FLOAT5 -- JSON5 floating point literal ** 6: FLOAT5 -- JSON5 floating point literal
** 7: TEXT -- Text literal acceptable to both SQL and JSON ** 7: TEXT -- Text literal acceptable to both SQL and JSON
** 8: TEXTJ -- Text literal with RFC-8259 escape codes ** 8: TEXTJ -- Text containing RFC-8259 escapes
** 9: TEXT5 -- Text literal with JSON5 and RFC-8259 escapes ** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes
** 10: TEXTRAW -- Text literal with unescaped ', ", or \ characters ** 10: TEXTRAW -- Text containing unescaped syntax characters
** 11: ARRAY ** 11: ARRAY
** 12: OBJECT ** 12: OBJECT
** **
@@ -118,10 +117,26 @@
#ifndef SQLITE_OMIT_JSON #ifndef SQLITE_OMIT_JSON
#include "sqliteInt.h" #include "sqliteInt.h"
/* JSONB element types
*/
#define JSONB_NULL 0 /* "null" */
#define JSONB_TRUE 1 /* "true" */
#define JSONB_FALSE 2 /* "false" */
#define JSONB_INT 3 /* integer acceptable to JSON and SQL */
#define JSONB_INT5 4 /* integer in 0x000 notation */
#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */
#define JSONB_FLOAT5 6 /* float with JSON5 extensions */
#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */
#define JSONB_TEXTJ 8 /* Text with JSON escapes */
#define JSONB_TEXT5 9 /* Text with JSON-5 escape */
#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */
#define JSONB_ARRAY 11 /* An array */
#define JSONB_OBJECT 12 /* An object */
/* /*
** Growing our own isspace() routine this way is twice as fast as ** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function, resulting in a 7% overall performance ** the library isspace() function, resulting in a 7% overall performance
** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/ */
static const char jsonIsSpace[] = { static const char jsonIsSpace[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
@@ -168,11 +183,12 @@ static const char jsonIsOk[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
}; };
/* Put code used only for testing inside the JSON_VVA() macro.
*/
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST) #if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
# define VVA(X) # define JSON_VVA(X)
#else #else
# define VVA(X) X # define JSON_VVA(X) X
#endif #endif
/* Objects */ /* Objects */
@@ -204,7 +220,7 @@ struct JsonCleanup {
void *pArg; /* Argument to xOp() */ void *pArg; /* Argument to xOp() */
}; };
/* JSON type values /* JSON type values for JsonNode.eType
*/ */
#define JSON_SUBST 0 /* Special edit node. Uses u.iPrev */ #define JSON_SUBST 0 /* Special edit node. Uses u.iPrev */
#define JSON_NULL 1 #define JSON_NULL 1
@@ -216,33 +232,18 @@ struct JsonCleanup {
#define JSON_ARRAY 7 #define JSON_ARRAY 7
#define JSON_OBJECT 8 #define JSON_OBJECT 8
/* JSON BLOB node types /* Human-readalbe names for the JsonNode types:
*/
#define JSONB_NULL 0 /* "null" */
#define JSONB_TRUE 1 /* "true" */
#define JSONB_FALSE 2 /* "false" */
#define JSONB_INT 3 /* integer acceptable to JSON and SQL */
#define JSONB_INT5 4 /* integer in 0x000 notation */
#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */
#define JSONB_FLOAT5 6 /* float with JSON5 extensions */
#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */
#define JSONB_TEXTJ 8 /* Text with JSON escapes */
#define JSONB_TEXT5 9 /* Text with JSON-5 escape */
#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */
#define JSONB_ARRAY 11 /* An array */
#define JSONB_OBJECT 12 /* An object */
/* The "subtype" set for JSON values */
#define JSON_SUBTYPE 74 /* Ascii for "J" */
/*
** Names of the various JSON types:
*/ */
static const char * const jsonType[] = { static const char * const jsonType[] = {
"subst", "subst",
"null", "true", "false", "integer", "real", "text", "array", "object" "null", "true", "false", "integer", "real", "text", "array", "object"
}; };
/* The "subtype" set for text JSON values passed through using
** sqlite3_result_subtype() and sqlite3_value_subtype().
*/
#define JSON_SUBTYPE 74 /* Ascii for "J" */
/* Bit values for the JsonNode.jnFlag field /* Bit values for the JsonNode.jnFlag field
*/ */
#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ #define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
@@ -350,9 +351,10 @@ struct JsonParse {
** Utility routines for dealing with JsonString objects ** Utility routines for dealing with JsonString objects
**************************************************************************/ **************************************************************************/
/* Set the JsonString object to an empty string /* Turn uninitialized bulk memory into a valid JsonString object
** holding a zero-length string.
*/ */
static void jsonZero(JsonString *p){ static void jsonStringZero(JsonString *p){
p->zBuf = p->zSpace; p->zBuf = p->zSpace;
p->nAlloc = sizeof(p->zSpace); p->nAlloc = sizeof(p->zSpace);
p->nUsed = 0; p->nUsed = 0;
@@ -361,39 +363,39 @@ static void jsonZero(JsonString *p){
/* Initialize the JsonString object /* Initialize the JsonString object
*/ */
static void jsonInit(JsonString *p, sqlite3_context *pCtx){ static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){
p->pCtx = pCtx; p->pCtx = pCtx;
p->bErr = 0; p->bErr = 0;
jsonZero(p); jsonStringZero(p);
} }
/* Free all allocated memory and reset the JsonString object back to its /* Free all allocated memory and reset the JsonString object back to its
** initial state. ** initial state.
*/ */
static void jsonReset(JsonString *p){ static void jsonStringReset(JsonString *p){
if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf); if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf);
jsonZero(p); jsonStringZero(p);
} }
/* Report an out-of-memory (OOM) condition /* Report an out-of-memory (OOM) condition
*/ */
static void jsonOom(JsonString *p){ static void jsonStringOom(JsonString *p){
p->bErr = 1; p->bErr = 1;
sqlite3_result_error_nomem(p->pCtx); sqlite3_result_error_nomem(p->pCtx);
jsonReset(p); jsonStringReset(p);
} }
/* Enlarge pJson->zBuf so that it can hold at least N more bytes. /* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success. Return non-zero on an OOM error ** Return zero on success. Return non-zero on an OOM error
*/ */
static int jsonGrow(JsonString *p, u32 N){ static int jsonStringGrow(JsonString *p, u32 N){
u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10; u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew; char *zNew;
if( p->bStatic ){ if( p->bStatic ){
if( p->bErr ) return 1; if( p->bErr ) return 1;
zNew = sqlite3RCStrNew(nTotal); zNew = sqlite3RCStrNew(nTotal);
if( zNew==0 ){ if( zNew==0 ){
jsonOom(p); jsonStringOom(p);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
memcpy(zNew, p->zBuf, (size_t)p->nUsed); memcpy(zNew, p->zBuf, (size_t)p->nUsed);
@@ -403,7 +405,7 @@ static int jsonGrow(JsonString *p, u32 N){
p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal); p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal);
if( p->zBuf==0 ){ if( p->zBuf==0 ){
p->bErr = 1; p->bErr = 1;
jsonZero(p); jsonStringZero(p);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
} }
@@ -413,20 +415,20 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string. /* Append N bytes from zIn onto the end of the JsonString string.
*/ */
static SQLITE_NOINLINE void jsonAppendExpand( static SQLITE_NOINLINE void jsonStringExpandAndAppend(
JsonString *p, JsonString *p,
const char *zIn, const char *zIn,
u32 N u32 N
){ ){
assert( N>0 ); assert( N>0 );
if( jsonGrow(p,N) ) return; if( jsonStringGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N); memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N; p->nUsed += N;
} }
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
if( N==0 ) return; if( N==0 ) return;
if( N+p->nUsed >= p->nAlloc ){ if( N+p->nUsed >= p->nAlloc ){
jsonAppendExpand(p,zIn,N); jsonStringExpandAndAppend(p,zIn,N);
}else{ }else{
memcpy(p->zBuf+p->nUsed, zIn, N); memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N; p->nUsed += N;
@@ -435,7 +437,7 @@ static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){ static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
assert( N>0 ); assert( N>0 );
if( N+p->nUsed >= p->nAlloc ){ if( N+p->nUsed >= p->nAlloc ){
jsonAppendExpand(p,zIn,N); jsonStringExpandAndAppend(p,zIn,N);
}else{ }else{
memcpy(p->zBuf+p->nUsed, zIn, N); memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N; p->nUsed += N;
@@ -447,7 +449,7 @@ static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
*/ */
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
va_list ap; va_list ap;
if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return;
va_start(ap, zFormat); va_start(ap, zFormat);
sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
va_end(ap); va_end(ap);
@@ -457,7 +459,7 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character /* Append a single character
*/ */
static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){ static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
if( jsonGrow(p,1) ) return; if( jsonStringGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c; p->zBuf[p->nUsed++] = c;
} }
static void jsonAppendChar(JsonString *p, char c){ static void jsonAppendChar(JsonString *p, char c){
@@ -480,7 +482,7 @@ static int jsonForceRCStr(JsonString *p){
if( p->bStatic==0 ) return 1; if( p->bStatic==0 ) return 1;
p->nAlloc = 0; p->nAlloc = 0;
p->nUsed++; p->nUsed++;
jsonGrow(p, p->nUsed); jsonStringGrow(p, p->nUsed);
p->nUsed--; p->nUsed--;
return p->bStatic==0; return p->bStatic==0;
} }
@@ -504,7 +506,8 @@ static void jsonAppendSeparator(JsonString *p){
*/ */
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
u32 i; u32 i;
if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return; if( zIn==0 ) return;
if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return;
p->zBuf[p->nUsed++] = '"'; p->zBuf[p->nUsed++] = '"';
for(i=0; i<N; i++){ for(i=0; i<N; i++){
unsigned char c = ((unsigned const char*)zIn)[i]; unsigned char c = ((unsigned const char*)zIn)[i];
@@ -512,7 +515,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
p->zBuf[p->nUsed++] = c; p->zBuf[p->nUsed++] = c;
}else if( c=='"' || c=='\\' ){ }else if( c=='"' || c=='\\' ){
json_simple_escape: json_simple_escape:
if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; if( (p->nUsed+N+3-i > p->nAlloc) && jsonStringGrow(p,N+3-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = '\\';
p->zBuf[p->nUsed++] = c; p->zBuf[p->nUsed++] = c;
}else if( c=='\'' ){ }else if( c=='\'' ){
@@ -533,7 +536,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
c = aSpecial[c]; c = aSpecial[c];
goto json_simple_escape; goto json_simple_escape;
} }
if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; if( (p->nUsed+N+7+i > p->nAlloc) && jsonStringGrow(p,N+7-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = '\\';
p->zBuf[p->nUsed++] = 'u'; p->zBuf[p->nUsed++] = 'u';
p->zBuf[p->nUsed++] = '0'; p->zBuf[p->nUsed++] = '0';
@@ -680,10 +683,10 @@ static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
/* /*
** Append a function parameter value to the JSON string under ** Append an sqlite3_value (such as a function parameter) to the JSON
** construction. ** string under construction in p.
*/ */
static void jsonAppendValue( static void jsonAppendSqlValue(
JsonString *p, /* Append to this JSON string */ JsonString *p, /* Append to this JSON string */
sqlite3_value *pValue /* Value to append */ sqlite3_value *pValue /* Value to append */
){ ){
@@ -716,7 +719,7 @@ static void jsonAppendValue(
if( p->bErr==0 ){ if( p->bErr==0 ){
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
p->bErr = 2; p->bErr = 2;
jsonReset(p); jsonStringReset(p);
} }
break; break;
} }
@@ -724,11 +727,12 @@ static void jsonAppendValue(
} }
/* Make the JSON in p the result of the SQL function. /* Make the text in p (which is probably a generated JSON text string)
** the result of the SQL function.
** **
** The JSON string is reset. ** The JsonString is reset.
*/ */
static void jsonResult(JsonString *p){ static void jsonReturnString(JsonString *p){
if( p->bErr==0 ){ if( p->bErr==0 ){
if( p->bStatic ){ if( p->bStatic ){
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
@@ -743,7 +747,7 @@ static void jsonResult(JsonString *p){
if( p->bErr==1 ){ if( p->bErr==1 ){
sqlite3_result_error_nomem(p->pCtx); sqlite3_result_error_nomem(p->pCtx);
} }
jsonReset(p); jsonStringReset(p);
} }
/************************************************************************** /**************************************************************************
@@ -842,7 +846,7 @@ static int jsonParseAddCleanup(
** append to pOut. Subsubstructure is also included. Return ** append to pOut. Subsubstructure is also included. Return
** the number of JsonNode objects that are encoded. ** the number of JsonNode objects that are encoded.
*/ */
static void jsonRenderNode( static void jsonRenderNodeAsText(
JsonParse *pParse, /* the complete parse of the JSON */ JsonParse *pParse, /* the complete parse of the JSON */
JsonNode *pNode, /* The node to render */ JsonNode *pNode, /* The node to render */
JsonString *pOut /* Write JSON here */ JsonString *pOut /* Write JSON here */
@@ -922,7 +926,7 @@ static void jsonRenderNode(
while( j<=pNode->n ){ while( j<=pNode->n ){
if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
jsonAppendSeparator(pOut); jsonAppendSeparator(pOut);
jsonRenderNode(pParse, &pNode[j], pOut); jsonRenderNodeAsText(pParse, &pNode[j], pOut);
} }
j += jsonNodeSize(&pNode[j]); j += jsonNodeSize(&pNode[j]);
} }
@@ -942,9 +946,9 @@ static void jsonRenderNode(
while( j<=pNode->n ){ while( j<=pNode->n ){
if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
jsonAppendSeparator(pOut); jsonAppendSeparator(pOut);
jsonRenderNode(pParse, &pNode[j], pOut); jsonRenderNodeAsText(pParse, &pNode[j], pOut);
jsonAppendChar(pOut, ':'); jsonAppendChar(pOut, ':');
jsonRenderNode(pParse, &pNode[j+1], pOut); jsonRenderNodeAsText(pParse, &pNode[j+1], pOut);
} }
j += 1 + jsonNodeSize(&pNode[j+1]); j += 1 + jsonNodeSize(&pNode[j+1]);
} }
@@ -968,9 +972,14 @@ static void jsonRenderNodeAsBlob(
); );
/* /*
** Return a JsonNode and all its descendants as a JSON string. ** Make the return value of an SQL function be the JSON encoded by pNode.
**
** By default, the node is rendered as RFC-8259 JSON text (canonical
** JSON text without any JSON-5 enhancements). However if the
** JSON_BLOB flag is set in the user-data for the function, then the
** node is rendered into the JSONB format and returned as a BLOB.
*/ */
static void jsonReturnJson( static void jsonReturnNodeAsJson(
JsonParse *pParse, /* The complete JSON */ JsonParse *pParse, /* The complete JSON */
JsonNode *pNode, /* Node to return */ JsonNode *pNode, /* Node to return */
sqlite3_context *pCtx, /* Return value for this function */ sqlite3_context *pCtx, /* Return value for this function */
@@ -992,13 +1001,13 @@ static void jsonReturnJson(
jsonRenderNodeAsBlob(pParse, pNode, &x); jsonRenderNodeAsBlob(pParse, pNode, &x);
sqlite3_result_blob(pCtx, x.aBlob, x.nBlob, sqlite3_free); sqlite3_result_blob(pCtx, x.aBlob, x.nBlob, sqlite3_free);
}else{ }else{
jsonInit(&s, pCtx); jsonStringInit(&s, pCtx);
jsonRenderNode(pParse, pNode, &s); jsonRenderNodeAsText(pParse, pNode, &s);
if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){ if( bGenerateAlt && pParse->zAlt==0 && jsonForceRCStr(&s) ){
pParse->zAlt = sqlite3RCStrRef(s.zBuf); pParse->zAlt = sqlite3RCStrRef(s.zBuf);
pParse->nAlt = s.nUsed; pParse->nAlt = s.nUsed;
} }
jsonResult(&s); jsonReturnString(&s);
sqlite3_result_subtype(pCtx, JSON_SUBTYPE); sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
} }
} }
@@ -1035,9 +1044,16 @@ static u32 jsonHexToInt4(const char *z){
} }
/* /*
** Make the JsonNode the return value of the function. ** Make the return value from an SQL function be the SQL value of
** JsonNode pNode.
**
** If pNode is an atom (not an array or object) then the value returned
** is a pure SQL value - an SQLITE_INTEGER, SQLITE_REAL, SQLITE_TEXT, or
** SQLITE_NULL. However, if pNode is a JSON array or object, then the
** value returned is either RFC-8259 JSON text or a BLOB in the JSONB
** format, depending on the JSON_BLOB flag of the function user-data.
*/ */
static void jsonReturn( static void jsonReturnNodeAsSql(
JsonParse *pParse, /* Complete JSON parse tree */ JsonParse *pParse, /* Complete JSON parse tree */
JsonNode *pNode, /* Node to return */ JsonNode *pNode, /* Node to return */
sqlite3_context *pCtx /* Return value for this function */ sqlite3_context *pCtx /* Return value for this function */
@@ -1194,7 +1210,7 @@ static void jsonReturn(
} }
case JSON_ARRAY: case JSON_ARRAY:
case JSON_OBJECT: { case JSON_OBJECT: {
jsonReturnJson(pParse, pNode, pCtx, 0); jsonReturnNodeAsJson(pParse, pNode, pCtx, 0);
break; break;
} }
} }
@@ -1265,7 +1281,7 @@ static int jsonParseAddNode(
assert( p!=0 ); assert( p!=0 );
p->eType = (u8)(eType & 0xff); p->eType = (u8)(eType & 0xff);
p->jnFlags = (u8)(eType >> 8); p->jnFlags = (u8)(eType >> 8);
VVA( p->eU = zContent ? 1 : 0 ); JSON_VVA( p->eU = zContent ? 1 : 0 );
p->n = n; p->n = n;
p->u.zJContent = zContent; p->u.zJContent = zContent;
return pParse->nNode++; return pParse->nNode++;
@@ -1490,7 +1506,7 @@ static const struct NanInfName {
** -4 ',' seen ** -4 ',' seen
** -5 ':' seen ** -5 ':' seen
*/ */
static int jsonParseValue(JsonParse *pParse, u32 i){ static int jsonParseValueFromText(JsonParse *pParse, u32 i){
char c; char c;
u32 j; u32 j;
int iThis; int iThis;
@@ -1509,7 +1525,7 @@ json_parse_restart:
} }
for(j=i+1;;j++){ for(j=i+1;;j++){
u32 nNode = pParse->nNode; u32 nNode = pParse->nNode;
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x<=0 ){ if( x<=0 ){
if( x==(-2) ){ if( x==(-2) ){
j = pParse->iErr; j = pParse->iErr;
@@ -1552,7 +1568,7 @@ json_parse_restart:
goto parse_object_value; goto parse_object_value;
} }
} }
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x!=(-5) ){ if( x!=(-5) ){
if( x!=(-1) ) pParse->iErr = j; if( x!=(-1) ) pParse->iErr = j;
return -1; return -1;
@@ -1560,7 +1576,7 @@ json_parse_restart:
j = pParse->iErr+1; j = pParse->iErr+1;
} }
parse_object_value: parse_object_value:
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x<=0 ){ if( x<=0 ){
if( x!=(-1) ) pParse->iErr = j; if( x!=(-1) ) pParse->iErr = j;
return -1; return -1;
@@ -1579,7 +1595,7 @@ json_parse_restart:
break; break;
} }
} }
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x==(-4) ){ if( x==(-4) ){
j = pParse->iErr; j = pParse->iErr;
continue; continue;
@@ -1606,7 +1622,7 @@ json_parse_restart:
} }
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u)); memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){ for(j=i+1;;j++){
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x<=0 ){ if( x<=0 ){
if( x==(-3) ){ if( x==(-3) ){
j = pParse->iErr; j = pParse->iErr;
@@ -1630,7 +1646,7 @@ json_parse_restart:
break; break;
} }
} }
x = jsonParseValue(pParse, j); x = jsonParseValueFromText(pParse, j);
if( x==(-4) ){ if( x==(-4) ){
j = pParse->iErr; j = pParse->iErr;
continue; continue;
@@ -1807,7 +1823,10 @@ json_parse_restart:
} }
if( c=='e' || c=='E' ){ if( c=='e' || c=='E' ){
if( z[j-1]<'0' ){ if( z[j-1]<'0' ){
if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){ if( ALWAYS(z[j-1]=='.')
&& ALWAYS(j-2>=i)
&& sqlite3Isdigit(z[j-2])
){
pParse->hasNonstd = 1; pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5; jnFlags |= JNODE_JSON5;
}else{ }else{
@@ -1952,12 +1971,14 @@ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
static int jsonParseValueFromBlob(JsonParse *pParse, u32 i); static int jsonParseValueFromBlob(JsonParse *pParse, u32 i);
/* /*
** Parse a complete JSON string. Return 0 on success or non-zero if there ** Parse JSON (either pure RFC-8259 JSON text, or JSON-5 text, or a JSONB
** are any errors. If an error occurs, free all memory held by pParse, ** blob) into the JsonNode representation.
** but not pParse itself.
** **
** pParse must be initialized to an empty parse object prior to calling ** Return 0 on success or non-zero if there are any errors.
** this routine. ** If an error occurs, free all memory held by pParse, but not pParse itself.
**
** pParse must be initialized with pParse->zJson set to the input text or
** blob prior to calling this routine.
*/ */
static int jsonParse( static int jsonParse(
JsonParse *pParse, /* Initialize and fill this JsonParse object */ JsonParse *pParse, /* Initialize and fill this JsonParse object */
@@ -1970,7 +1991,7 @@ static int jsonParse(
pParse->nBlob = pParse->nJson; pParse->nBlob = pParse->nJson;
i = jsonParseValueFromBlob(pParse, 0); i = jsonParseValueFromBlob(pParse, 0);
}else{ }else{
i = jsonParseValue(pParse, 0); i = jsonParseValueFromText(pParse, 0);
} }
if( pParse->oom ) i = -1; if( pParse->oom ) i = -1;
if( !pParse->isBinary && i>0 ){ if( !pParse->isBinary && i>0 ){
@@ -2279,7 +2300,7 @@ static JsonNode *jsonLookupStep(
assert( pRoot->eU==0 ); assert( pRoot->eU==0 );
pRoot->u.iAppend = iStart; pRoot->u.iAppend = iStart;
pRoot->jnFlags |= JNODE_APPEND; pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 ); JSON_VVA( pRoot->eU = 2 );
pParse->aNode[iLabel].jnFlags |= JNODE_RAW; pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
} }
return pNode; return pNode;
@@ -2298,7 +2319,9 @@ static JsonNode *jsonLookupStep(
if( pRoot->eType!=JSON_ARRAY ) return 0; if( pRoot->eType!=JSON_ARRAY ) return 0;
for(;;){ for(;;){
while( j<=pBase->n ){ while( j<=pBase->n ){
if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++; if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ){
i++;
}
j += jsonNodeSize(&pBase[j]); j += jsonNodeSize(&pBase[j]);
} }
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break; if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
@@ -2360,7 +2383,7 @@ static JsonNode *jsonLookupStep(
assert( pRoot->eU==0 ); assert( pRoot->eU==0 );
pRoot->u.iAppend = iStart; pRoot->u.iAppend = iStart;
pRoot->jnFlags |= JNODE_APPEND; pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 ); JSON_VVA( pRoot->eU = 2 );
} }
return pNode; return pNode;
} }
@@ -3758,9 +3781,9 @@ static void jsonReturnTextJsonFromBlob(
memset(&x, 0, sizeof(x)); memset(&x, 0, sizeof(x));
x.aBlob = (u8*)aBlob; x.aBlob = (u8*)aBlob;
x.nBlob = nBlob; x.nBlob = nBlob;
jsonInit(&s, ctx); jsonStringInit(&s, ctx);
jsonRenderBlob(&x, 0, &s); jsonRenderBlob(&x, 0, &s);
jsonResult(&s); jsonReturnString(&s);
} }
@@ -4050,7 +4073,7 @@ static void jsonParseFunc(
printf("iSubst = %u\n", p->iSubst); printf("iSubst = %u\n", p->iSubst);
printf("iHold = %u\n", p->iHold); printf("iHold = %u\n", p->iHold);
jsonDebugPrintNodeEntries(p->aNode, p->nNode); jsonDebugPrintNodeEntries(p->aNode, p->nNode);
jsonReturnJson(p, p->aNode, ctx, 1); jsonReturnNodeAsJson(p, p->aNode, ctx, 1);
} }
/* /*
@@ -4156,9 +4179,9 @@ static void jsonQuoteFunc(
JsonString jx; JsonString jx;
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
jsonInit(&jx, ctx); jsonStringInit(&jx, ctx);
jsonAppendValue(&jx, argv[0]); jsonAppendSqlValue(&jx, argv[0]);
jsonResult(&jx); jsonReturnString(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE); sqlite3_result_subtype(ctx, JSON_SUBTYPE);
} }
@@ -4175,14 +4198,14 @@ static void jsonArrayFunc(
int i; int i;
JsonString jx; JsonString jx;
jsonInit(&jx, ctx); jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '['); jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){ for(i=0; i<argc; i++){
jsonAppendSeparator(&jx); jsonAppendSeparator(&jx);
jsonAppendValue(&jx, argv[i]); jsonAppendSqlValue(&jx, argv[i]);
} }
jsonAppendChar(&jx, ']'); jsonAppendChar(&jx, ']');
jsonResult(&jx); jsonReturnString(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE); sqlite3_result_subtype(ctx, JSON_SUBTYPE);
} }
@@ -4284,7 +4307,7 @@ static void jsonExtractFunc(
** LABEL ==> $.LABEL // PG compatible ** LABEL ==> $.LABEL // PG compatible
** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
*/ */
jsonInit(&jx, ctx); jsonStringInit(&jx, ctx);
if( sqlite3Isdigit(zPath[0]) ){ if( sqlite3Isdigit(zPath[0]) ){
jsonAppendRawNZ(&jx, "$[", 2); jsonAppendRawNZ(&jx, "$[", 2);
jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
@@ -4295,27 +4318,27 @@ static void jsonExtractFunc(
jsonAppendChar(&jx, 0); jsonAppendChar(&jx, 0);
} }
pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx); pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
jsonReset(&jx); jsonStringReset(&jx);
}else{ }else{
pNode = jsonLookup(p, zPath, 0, ctx); pNode = jsonLookup(p, zPath, 0, ctx);
} }
if( pNode ){ if( pNode ){
if( flags & JSON_JSON ){ if( flags & JSON_JSON ){
jsonReturnJson(p, pNode, ctx, 0); jsonReturnNodeAsJson(p, pNode, ctx, 0);
}else{ }else{
jsonReturn(p, pNode, ctx); jsonReturnNodeAsSql(p, pNode, ctx);
sqlite3_result_subtype(ctx, 0); sqlite3_result_subtype(ctx, 0);
} }
} }
}else{ }else{
pNode = jsonLookup(p, zPath, 0, ctx); pNode = jsonLookup(p, zPath, 0, ctx);
if( p->nErr==0 && pNode ) jsonReturn(p, pNode, ctx); if( p->nErr==0 && pNode ) jsonReturnNodeAsSql(p, pNode, ctx);
} }
}else{ }else{
/* Two or more PATH arguments results in a JSON array with each /* Two or more PATH arguments results in a JSON array with each
** element of the array being the value selected by one of the PATHs */ ** element of the array being the value selected by one of the PATHs */
int i; int i;
jsonInit(&jx, ctx); jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '['); jsonAppendChar(&jx, '[');
for(i=1; i<argc; i++){ for(i=1; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]); zPath = (const char*)sqlite3_value_text(argv[i]);
@@ -4323,17 +4346,17 @@ static void jsonExtractFunc(
if( p->nErr ) break; if( p->nErr ) break;
jsonAppendSeparator(&jx); jsonAppendSeparator(&jx);
if( pNode ){ if( pNode ){
jsonRenderNode(p, pNode, &jx); jsonRenderNodeAsText(p, pNode, &jx);
}else{ }else{
jsonAppendRawNZ(&jx, "null", 4); jsonAppendRawNZ(&jx, "null", 4);
} }
} }
if( i==argc ){ if( i==argc ){
jsonAppendChar(&jx, ']'); jsonAppendChar(&jx, ']');
jsonResult(&jx); jsonReturnString(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE); sqlite3_result_subtype(ctx, JSON_SUBTYPE);
} }
jsonReset(&jx); jsonStringReset(&jx);
} }
} }
@@ -4399,7 +4422,7 @@ static JsonNode *jsonMergePatch(
pParse->aNode[iStart].n = 1+nApnd; pParse->aNode[iStart].n = 1+nApnd;
pParse->aNode[iRoot].jnFlags |= JNODE_APPEND; pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
pParse->aNode[iRoot].u.iAppend = iStart; pParse->aNode[iRoot].u.iAppend = iStart;
VVA( pParse->aNode[iRoot].eU = 2 ); JSON_VVA( pParse->aNode[iRoot].eU = 2 );
iRoot = iStart; iRoot = iStart;
pTarget = &pParse->aNode[iTarget]; pTarget = &pParse->aNode[iTarget];
} }
@@ -4435,7 +4458,7 @@ static void jsonPatchFunc(
if( pResult && pX->oom==0 ){ if( pResult && pX->oom==0 ){
jsonDebugPrintParse(pX); jsonDebugPrintParse(pX);
jsonDebugPrintNode(pResult); jsonDebugPrintNode(pResult);
jsonReturnJson(pX, pResult, ctx, 0); jsonReturnNodeAsJson(pX, pResult, ctx, 0);
}else{ }else{
sqlite3_result_error_nomem(ctx); sqlite3_result_error_nomem(ctx);
} }
@@ -4462,12 +4485,12 @@ static void jsonObjectFunc(
"of arguments", -1); "of arguments", -1);
return; return;
} }
jsonInit(&jx, ctx); jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '{'); jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){ for(i=0; i<argc; i+=2){
if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1); sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
jsonReset(&jx); jsonStringReset(&jx);
return; return;
} }
jsonAppendSeparator(&jx); jsonAppendSeparator(&jx);
@@ -4475,10 +4498,10 @@ static void jsonObjectFunc(
n = (u32)sqlite3_value_bytes(argv[i]); n = (u32)sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n); jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':'); jsonAppendChar(&jx, ':');
jsonAppendValue(&jx, argv[i+1]); jsonAppendSqlValue(&jx, argv[i+1]);
} }
jsonAppendChar(&jx, '}'); jsonAppendChar(&jx, '}');
jsonResult(&jx); jsonReturnString(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE); sqlite3_result_subtype(ctx, JSON_SUBTYPE);
} }
@@ -4514,7 +4537,7 @@ static void jsonRemoveFunc(
} }
} }
if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){ if( (pParse->aNode[0].jnFlags & JNODE_REMOVE)==0 ){
jsonReturnJson(pParse, pParse->aNode, ctx, 1); jsonReturnNodeAsJson(pParse, pParse->aNode, ctx, 1);
} }
remove_done: remove_done:
jsonDebugPrintParse(p); jsonDebugPrintParse(p);
@@ -4640,7 +4663,7 @@ static void jsonReplaceFunc(
jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]); jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
} }
} }
jsonReturnJson(pParse, pParse->aNode, ctx, 1); jsonReturnNodeAsJson(pParse, pParse->aNode, ctx, 1);
replace_err: replace_err:
jsonDebugPrintParse(pParse); jsonDebugPrintParse(pParse);
} }
@@ -4692,7 +4715,7 @@ static void jsonSetFunc(
} }
} }
jsonDebugPrintParse(pParse); jsonDebugPrintParse(pParse);
jsonReturnJson(pParse, pParse->aNode, ctx, 1); jsonReturnNodeAsJson(pParse, pParse->aNode, ctx, 1);
jsonSetDone: jsonSetDone:
/* no cleanup required */; /* no cleanup required */;
@@ -4830,13 +4853,13 @@ static void jsonArrayStep(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){ if( pStr ){
if( pStr->zBuf==0 ){ if( pStr->zBuf==0 ){
jsonInit(pStr, ctx); jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '['); jsonAppendChar(pStr, '[');
}else if( pStr->nUsed>1 ){ }else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ','); jsonAppendChar(pStr, ',');
} }
pStr->pCtx = ctx; pStr->pCtx = ctx;
jsonAppendValue(pStr, argv[0]); jsonAppendSqlValue(pStr, argv[0]);
} }
} }
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
@@ -4936,7 +4959,7 @@ static void jsonObjectStep(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){ if( pStr ){
if( pStr->zBuf==0 ){ if( pStr->zBuf==0 ){
jsonInit(pStr, ctx); jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{'); jsonAppendChar(pStr, '{');
}else if( pStr->nUsed>1 ){ }else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ','); jsonAppendChar(pStr, ',');
@@ -4946,7 +4969,7 @@ static void jsonObjectStep(
n = (u32)sqlite3_value_bytes(argv[0]); n = (u32)sqlite3_value_bytes(argv[0]);
jsonAppendString(pStr, z, n); jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':'); jsonAppendChar(pStr, ':');
jsonAppendValue(pStr, argv[1]); jsonAppendSqlValue(pStr, argv[1]);
} }
} }
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
@@ -5110,7 +5133,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
if( pUp->eType==JSON_ARRAY ){ if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==0 || pUp->eU==3 ); assert( pUp->eU==0 || pUp->eU==3 );
testcase( pUp->eU==3 ); testcase( pUp->eU==3 );
VVA( pUp->eU = 3 ); JSON_VVA( pUp->eU = 3 );
if( iUp==p->i-1 ){ if( iUp==p->i-1 ){
pUp->u.iKey = 0; pUp->u.iKey = 0;
}else{ }else{
@@ -5208,7 +5231,7 @@ static int jsonEachColumn(
case JEACH_KEY: { case JEACH_KEY: {
if( p->i==0 ) break; if( p->i==0 ) break;
if( p->eType==JSON_OBJECT ){ if( p->eType==JSON_OBJECT ){
jsonReturn(&p->sParse, pThis, ctx); jsonReturnNodeAsSql(&p->sParse, pThis, ctx);
}else if( p->eType==JSON_ARRAY ){ }else if( p->eType==JSON_ARRAY ){
u32 iKey; u32 iKey;
if( p->bRecursive ){ if( p->bRecursive ){
@@ -5224,7 +5247,7 @@ static int jsonEachColumn(
} }
case JEACH_VALUE: { case JEACH_VALUE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->jnFlags & JNODE_LABEL ) pThis++;
jsonReturn(&p->sParse, pThis, ctx); jsonReturnNodeAsSql(&p->sParse, pThis, ctx);
break; break;
} }
case JEACH_TYPE: { case JEACH_TYPE: {
@@ -5235,7 +5258,7 @@ static int jsonEachColumn(
case JEACH_ATOM: { case JEACH_ATOM: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->jnFlags & JNODE_LABEL ) pThis++;
if( pThis->eType>=JSON_ARRAY ) break; if( pThis->eType>=JSON_ARRAY ) break;
jsonReturn(&p->sParse, pThis, ctx); jsonReturnNodeAsSql(&p->sParse, pThis, ctx);
break; break;
} }
case JEACH_ID: { case JEACH_ID: {
@@ -5251,7 +5274,7 @@ static int jsonEachColumn(
} }
case JEACH_FULLKEY: { case JEACH_FULLKEY: {
JsonString x; JsonString x;
jsonInit(&x, ctx); jsonStringInit(&x, ctx);
if( p->bRecursive ){ if( p->bRecursive ){
jsonEachComputePath(p, &x, p->i); jsonEachComputePath(p, &x, p->i);
}else{ }else{
@@ -5266,15 +5289,15 @@ static int jsonEachColumn(
jsonAppendObjectPathElement(&x, pThis); jsonAppendObjectPathElement(&x, pThis);
} }
} }
jsonResult(&x); jsonReturnString(&x);
break; break;
} }
case JEACH_PATH: { case JEACH_PATH: {
if( p->bRecursive ){ if( p->bRecursive ){
JsonString x; JsonString x;
jsonInit(&x, ctx); jsonStringInit(&x, ctx);
jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
jsonResult(&x); jsonReturnString(&x);
break; break;
} }
/* For json_each() path and root are the same so fall through /* For json_each() path and root are the same so fall through
@@ -5444,7 +5467,7 @@ static int jsonEachFilter(
p->eType = pNode->eType; p->eType = pNode->eType;
if( p->eType>=JSON_ARRAY ){ if( p->eType>=JSON_ARRAY ){
assert( pNode->eU==0 ); assert( pNode->eU==0 );
VVA( pNode->eU = 3 ); JSON_VVA( pNode->eU = 3 );
pNode->u.iKey = 0; pNode->u.iKey = 0;
p->iEnd = p->i + pNode->n + 1; p->iEnd = p->i + pNode->n + 1;
if( p->bRecursive ){ if( p->bRecursive ){