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:
12
manifest
12
manifest
@@ -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.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1c0cba3461d6111b3aeb77726880221f1240355f0b57e060febbdeb12fb688c0
|
9b620d813ef483f1277c1683c5e926a882f07f3b90804dea0c91b325ff8e45a4
|
||||||
285
src/json.c
285
src/json.c
@@ -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 ){
|
||||||
|
|||||||
Reference in New Issue
Block a user