mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Incremental progress toward getting json_each() and json_tree() to work
directly off of a JSONB blob. FossilOrigin-Name: f8cab41b3bc65af6ff34b481db693d640ea025d09463d50b8e56d855e2abc913
This commit is contained in:
15
manifest
15
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sjsonParseReset()\sto\sproperly\sclear\sthe\sJsonParse.aBlob\selement.
|
C Incremental\sprogress\stoward\sgetting\sjson_each()\sand\sjson_tree()\sto\swork\ndirectly\soff\sof\sa\sJSONB\sblob.
|
||||||
D 2023-11-24T14:25:56.679
|
D 2023-11-24T18:44:00.124
|
||||||
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
|
||||||
@@ -688,7 +688,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 c6b23115b4561008363346a209b5c8a3538d967b35c63685b2e07dc7de1f1e31
|
F src/json.c 1b9cc57728bc3a420bae5f4ae8233dcd2c3a337f00a2467346f7b788aedf1ba0
|
||||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||||
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
||||||
@@ -2145,8 +2145,11 @@ 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 7dbc2f496d7a362460bb4c262ecafe5f30e35a8744861163d12c996365c2142f
|
P ab2644aacf4757a51cf62e05cff6711a0a3605d60502a3dd310887df1b993545
|
||||||
R 1676f3ca8710b44ac390888e709fad02
|
R b8a3524be145a961ee4bfad02645fa25
|
||||||
|
T *branch * jsonb-tree
|
||||||
|
T *sym-jsonb-tree *
|
||||||
|
T -sym-jsonb *
|
||||||
U drh
|
U drh
|
||||||
Z 41b7b01f3bc28811bfbbf765da2aea03
|
Z b88ae8be743d3b0432d41e7f9773a471
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ab2644aacf4757a51cf62e05cff6711a0a3605d60502a3dd310887df1b993545
|
f8cab41b3bc65af6ff34b481db693d640ea025d09463d50b8e56d855e2abc913
|
||||||
483
src/json.c
483
src/json.c
@@ -133,6 +133,14 @@
|
|||||||
#define JSONB_ARRAY 11 /* An array */
|
#define JSONB_ARRAY 11 /* An array */
|
||||||
#define JSONB_OBJECT 12 /* An object */
|
#define JSONB_OBJECT 12 /* An object */
|
||||||
|
|
||||||
|
/* Human-readalbe names for the JSONB values:
|
||||||
|
*/
|
||||||
|
static const char * const jsonbType[] = {
|
||||||
|
"null", "true", "false", "integer", "integer",
|
||||||
|
"real", "real", "text", "text", "text",
|
||||||
|
"text", "array", "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
|
||||||
@@ -4070,7 +4078,8 @@ static void jsonReturnTextJsonFromBlob(
|
|||||||
static void jsonReturnFromBlob(
|
static void jsonReturnFromBlob(
|
||||||
JsonParse *pParse, /* Complete JSON parse tree */
|
JsonParse *pParse, /* Complete JSON parse tree */
|
||||||
u32 i, /* Index of the node */
|
u32 i, /* Index of the node */
|
||||||
sqlite3_context *pCtx /* Return value for this function */
|
sqlite3_context *pCtx, /* Return value for this function */
|
||||||
|
int textOnly /* return text JSON. Disregard user-data */
|
||||||
){
|
){
|
||||||
u32 n, sz;
|
u32 n, sz;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -4217,7 +4226,7 @@ static void jsonReturnFromBlob(
|
|||||||
}
|
}
|
||||||
case JSONB_ARRAY:
|
case JSONB_ARRAY:
|
||||||
case JSONB_OBJECT: {
|
case JSONB_OBJECT: {
|
||||||
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx));
|
int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx));
|
||||||
if( flags & JSON_BLOB ){
|
if( flags & JSON_BLOB ){
|
||||||
sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
|
sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
|
||||||
}else{
|
}else{
|
||||||
@@ -4280,7 +4289,7 @@ static void jsonExtractFromBlob(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( i<px.nBlob ){
|
if( i<px.nBlob ){
|
||||||
jsonReturnFromBlob(&px, i, ctx);
|
jsonReturnFromBlob(&px, i, ctx, 0);
|
||||||
}else if( i==JSON_BLOB_NOTFOUND ){
|
}else if( i==JSON_BLOB_NOTFOUND ){
|
||||||
return; /* Return NULL if not found */
|
return; /* Return NULL if not found */
|
||||||
}else if( i==JSON_BLOB_ERROR ){
|
}else if( i==JSON_BLOB_ERROR ){
|
||||||
@@ -5564,19 +5573,36 @@ static void jsonObjectFinal(sqlite3_context *ctx){
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** The json_each virtual table
|
** The json_each virtual table
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
typedef struct JsonParent JsonParent;
|
||||||
|
struct JsonParent {
|
||||||
|
u32 iHead; /* Start of object or array */
|
||||||
|
u32 iEnd; /* First byte past the end */
|
||||||
|
i64 iKey; /* Key for JSONB_ARRAY */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct JsonEachCursor JsonEachCursor;
|
typedef struct JsonEachCursor JsonEachCursor;
|
||||||
struct JsonEachCursor {
|
struct JsonEachCursor {
|
||||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||||
u32 iRowid; /* The rowid */
|
u32 iRowid; /* The rowid */
|
||||||
u32 iBegin; /* The first node of the scan */
|
u32 iBegin; /* The first node of the scan */
|
||||||
u32 i; /* Index in sParse.aNode[] of current row */
|
u32 i; /* Index in sParse.aBlob[] of current row */
|
||||||
u32 iEnd; /* EOF when i equals or exceeds this value */
|
u32 iEnd; /* EOF when i equals or exceeds this value */
|
||||||
u8 eType; /* Type of top-level element */
|
u8 eType; /* Type of the container for element i */
|
||||||
u8 bRecursive; /* True for json_tree(). False for json_each() */
|
u8 bRecursive; /* True for json_tree(). False for json_each() */
|
||||||
|
u32 nParent; /* Current nesting depth */
|
||||||
|
u32 nParentAlloc; /* Space allocated for aParent[] */
|
||||||
|
JsonParent *aParent; /* Parent elements of i */
|
||||||
char *zJson; /* Input JSON */
|
char *zJson; /* Input JSON */
|
||||||
char *zRoot; /* Path by which to filter zJson */
|
char *zRoot; /* Path by which to filter zJson */
|
||||||
|
sqlite3 *db; /* Database connection */
|
||||||
JsonParse sParse; /* Parse of the input JSON */
|
JsonParse sParse; /* Parse of the input JSON */
|
||||||
};
|
};
|
||||||
|
typedef struct JsonEachConnection JsonEachConnection;
|
||||||
|
struct JsonEachConnection {
|
||||||
|
sqlite3_vtab base; /* Base class - must be first */
|
||||||
|
sqlite3 *db; /* Database connection */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Constructor for the json_each virtual table */
|
/* Constructor for the json_each virtual table */
|
||||||
static int jsonEachConnect(
|
static int jsonEachConnect(
|
||||||
@@ -5586,7 +5612,7 @@ static int jsonEachConnect(
|
|||||||
sqlite3_vtab **ppVtab,
|
sqlite3_vtab **ppVtab,
|
||||||
char **pzErr
|
char **pzErr
|
||||||
){
|
){
|
||||||
sqlite3_vtab *pNew;
|
JsonEachConnection *pNew;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Column numbers */
|
/* Column numbers */
|
||||||
@@ -5612,10 +5638,11 @@ static int jsonEachConnect(
|
|||||||
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
|
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
|
||||||
"json HIDDEN,root HIDDEN)");
|
"json HIDDEN,root HIDDEN)");
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
pNew = (JsonEachConnection*)(*ppVtab = sqlite3_malloc( sizeof(*pNew) ));
|
||||||
if( pNew==0 ) return SQLITE_NOMEM;
|
if( pNew==0 ) return SQLITE_NOMEM;
|
||||||
memset(pNew, 0, sizeof(*pNew));
|
memset(pNew, 0, sizeof(*pNew));
|
||||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||||
|
pNew->db = db;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -5628,12 +5655,14 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){
|
|||||||
|
|
||||||
/* constructor for a JsonEachCursor object for json_each(). */
|
/* constructor for a JsonEachCursor object for json_each(). */
|
||||||
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||||
|
JsonEachConnection *pVtab = (JsonEachConnection*)p;
|
||||||
JsonEachCursor *pCur;
|
JsonEachCursor *pCur;
|
||||||
|
|
||||||
UNUSED_PARAMETER(p);
|
UNUSED_PARAMETER(p);
|
||||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||||
if( pCur==0 ) return SQLITE_NOMEM;
|
if( pCur==0 ) return SQLITE_NOMEM;
|
||||||
memset(pCur, 0, sizeof(*pCur));
|
memset(pCur, 0, sizeof(*pCur));
|
||||||
|
pCur->db = pVtab->db;
|
||||||
*ppCursor = &pCur->base;
|
*ppCursor = &pCur->base;
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -5653,8 +5682,12 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|||||||
static void jsonEachCursorReset(JsonEachCursor *p){
|
static void jsonEachCursorReset(JsonEachCursor *p){
|
||||||
sqlite3_free(p->zRoot);
|
sqlite3_free(p->zRoot);
|
||||||
jsonParseReset(&p->sParse);
|
jsonParseReset(&p->sParse);
|
||||||
|
sqlite3DbFree(p->db, p->aParent);
|
||||||
p->iRowid = 0;
|
p->iRowid = 0;
|
||||||
p->i = 0;
|
p->i = 0;
|
||||||
|
p->aParent = 0;
|
||||||
|
p->nParent = 0;
|
||||||
|
p->nParentAlloc = 0;
|
||||||
p->iEnd = 0;
|
p->iEnd = 0;
|
||||||
p->eType = 0;
|
p->eType = 0;
|
||||||
p->zJson = 0;
|
p->zJson = 0;
|
||||||
@@ -5676,45 +5709,106 @@ static int jsonEachEof(sqlite3_vtab_cursor *cur){
|
|||||||
return p->i >= p->iEnd;
|
return p->i >= p->iEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If the cursor is currently pointing at the label of a object entry,
|
||||||
|
** then return the index of the value. For all other cases, return the
|
||||||
|
** current pointer position, which is the value.
|
||||||
|
*/
|
||||||
|
static int jsonSkipLabel(JsonEachCursor *p){
|
||||||
|
if( p->eType==JSONB_OBJECT ){
|
||||||
|
u32 sz = 0;
|
||||||
|
u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz);
|
||||||
|
return p->i + n + sz;
|
||||||
|
}else{
|
||||||
|
return p->i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Advance the cursor to the next element for json_tree() */
|
/* Advance the cursor to the next element for json_tree() */
|
||||||
static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
||||||
JsonEachCursor *p = (JsonEachCursor*)cur;
|
JsonEachCursor *p = (JsonEachCursor*)cur;
|
||||||
if( p->bRecursive ){
|
if( p->sParse.aNode ){
|
||||||
if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
|
/* LEGACY */
|
||||||
p->i++;
|
if( p->bRecursive ){
|
||||||
p->iRowid++;
|
if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
|
||||||
if( p->i<p->iEnd ){
|
p->i++;
|
||||||
u32 iUp = p->sParse.aUp[p->i];
|
p->iRowid++;
|
||||||
JsonNode *pUp = &p->sParse.aNode[iUp];
|
if( p->i<p->iEnd ){
|
||||||
p->eType = pUp->eType;
|
u32 iUp = p->sParse.aUp[p->i];
|
||||||
if( pUp->eType==JSON_ARRAY ){
|
JsonNode *pUp = &p->sParse.aNode[iUp];
|
||||||
assert( pUp->eU==0 || pUp->eU==3 );
|
p->eType = pUp->eType;
|
||||||
testcase( pUp->eU==3 );
|
if( pUp->eType==JSON_ARRAY ){
|
||||||
JSON_VVA( pUp->eU = 3 );
|
assert( pUp->eU==0 || pUp->eU==3 );
|
||||||
if( iUp==p->i-1 ){
|
testcase( pUp->eU==3 );
|
||||||
pUp->u.iKey = 0;
|
JSON_VVA( pUp->eU = 3 );
|
||||||
}else{
|
if( iUp==p->i-1 ){
|
||||||
pUp->u.iKey++;
|
pUp->u.iKey = 0;
|
||||||
|
}else{
|
||||||
|
pUp->u.iKey++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
switch( p->eType ){
|
||||||
|
case JSON_ARRAY: {
|
||||||
|
p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
|
||||||
|
p->iRowid++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JSON_OBJECT: {
|
||||||
|
p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
|
||||||
|
p->iRowid++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
p->i = p->iEnd;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
return SQLITE_OK;
|
||||||
switch( p->eType ){
|
}else if( p->bRecursive ){
|
||||||
case JSON_ARRAY: {
|
u8 x;
|
||||||
p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
|
u8 levelChange = 0;
|
||||||
p->iRowid++;
|
u32 n, sz = 0;
|
||||||
break;
|
u32 i = jsonSkipLabel(p);
|
||||||
|
x = p->sParse.aBlob[i] & 0x0f;
|
||||||
|
n = jsonbPayloadSize(&p->sParse, p->i, &sz);
|
||||||
|
if( x==JSONB_OBJECT || x==JSONB_ARRAY ){
|
||||||
|
JsonParent *pParent;
|
||||||
|
if( p->nParent>=p->nParentAlloc ){
|
||||||
|
JsonParent *pNew;
|
||||||
|
u64 nNew;
|
||||||
|
nNew = p->nParentAlloc*2 + 3;
|
||||||
|
pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
|
||||||
|
if( pNew==0 ) return SQLITE_NOMEM;
|
||||||
|
p->nParentAlloc = (u32)nNew;
|
||||||
|
p->aParent = pNew;
|
||||||
|
levelChange = 1;
|
||||||
}
|
}
|
||||||
case JSON_OBJECT: {
|
pParent = &p->aParent[p->nParent++];
|
||||||
p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
|
pParent->iHead = p->i;
|
||||||
p->iRowid++;
|
pParent->iEnd = p->i + n + sz;
|
||||||
break;
|
pParent->iKey = 0;
|
||||||
}
|
}else{
|
||||||
default: {
|
p->i = i + n + sz;
|
||||||
p->i = p->iEnd;
|
}
|
||||||
break;
|
if( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
|
||||||
|
p->nParent--;
|
||||||
|
levelChange = 1;
|
||||||
|
}
|
||||||
|
if( levelChange ){
|
||||||
|
if( p->nParent>0 ){
|
||||||
|
p->eType = p->sParse.aBlob[p->aParent[p->nParent-1].iHead] & 0x0f;
|
||||||
|
}else{
|
||||||
|
p->eType = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
u32 n, sz = 0;
|
||||||
|
u32 i = jsonSkipLabel(p);
|
||||||
|
n = jsonbPayloadSize(&p->sParse, i, &sz);
|
||||||
|
p->i = i + n + sz;
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -5722,7 +5816,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
|||||||
/* Append an object label to the JSON Path being constructed
|
/* Append an object label to the JSON Path being constructed
|
||||||
** in pStr.
|
** in pStr.
|
||||||
*/
|
*/
|
||||||
static void jsonAppendObjectPathElement(
|
static void jsonAppendObjectPathElementOfNode(
|
||||||
JsonString *pStr,
|
JsonString *pStr,
|
||||||
JsonNode *pNode
|
JsonNode *pNode
|
||||||
){
|
){
|
||||||
@@ -5763,18 +5857,23 @@ static void jsonEachComputePath(
|
|||||||
jsonAppendChar(pStr, '$');
|
jsonAppendChar(pStr, '$');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iUp = p->sParse.aUp[i];
|
if( p->sParse.aNode ){
|
||||||
jsonEachComputePath(p, pStr, iUp);
|
/* LEGACY */
|
||||||
pNode = &p->sParse.aNode[i];
|
assert( p->sParse.aUp );
|
||||||
pUp = &p->sParse.aNode[iUp];
|
iUp = p->sParse.aUp[i];
|
||||||
if( pUp->eType==JSON_ARRAY ){
|
jsonEachComputePath(p, pStr, iUp);
|
||||||
assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
|
pNode = &p->sParse.aNode[i];
|
||||||
testcase( pUp->eU==0 );
|
pUp = &p->sParse.aNode[iUp];
|
||||||
jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
|
if( pUp->eType==JSON_ARRAY ){
|
||||||
}else{
|
assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
|
||||||
assert( pUp->eType==JSON_OBJECT );
|
testcase( pUp->eU==0 );
|
||||||
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
|
jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
|
||||||
jsonAppendObjectPathElement(pStr, pNode);
|
}else{
|
||||||
|
assert( pUp->eType==JSON_OBJECT );
|
||||||
|
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
|
||||||
|
jsonAppendObjectPathElementOfNode(pStr, pNode);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5782,102 +5881,200 @@ static void jsonEachComputePath(
|
|||||||
static int jsonEachColumn(
|
static int jsonEachColumn(
|
||||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||||
int i /* Which column to return */
|
int iColumn /* Which column to return */
|
||||||
){
|
){
|
||||||
JsonEachCursor *p = (JsonEachCursor*)cur;
|
JsonEachCursor *p = (JsonEachCursor*)cur;
|
||||||
JsonNode *pThis = &p->sParse.aNode[p->i];
|
if( p->sParse.aNode!=0 ){
|
||||||
switch( i ){
|
/* LEGACY */
|
||||||
case JEACH_KEY: {
|
JsonNode *pThis = &p->sParse.aNode[p->i];
|
||||||
if( p->i==0 ) break;
|
switch( iColumn ){
|
||||||
if( p->eType==JSON_OBJECT ){
|
case JEACH_KEY: {
|
||||||
|
if( p->i==0 ) break;
|
||||||
|
if( p->eType==JSON_OBJECT ){
|
||||||
|
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
||||||
|
}else if( p->eType==JSON_ARRAY ){
|
||||||
|
u32 iKey;
|
||||||
|
if( p->bRecursive ){
|
||||||
|
if( p->iRowid==0 ) break;
|
||||||
|
assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
|
||||||
|
iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
|
||||||
|
}else{
|
||||||
|
iKey = p->iRowid;
|
||||||
|
}
|
||||||
|
sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_VALUE: {
|
||||||
|
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
||||||
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
||||||
}else if( p->eType==JSON_ARRAY ){
|
break;
|
||||||
u32 iKey;
|
|
||||||
if( p->bRecursive ){
|
|
||||||
if( p->iRowid==0 ) break;
|
|
||||||
assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
|
|
||||||
iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
|
|
||||||
}else{
|
|
||||||
iKey = p->iRowid;
|
|
||||||
}
|
|
||||||
sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
|
|
||||||
}
|
}
|
||||||
break;
|
case JEACH_TYPE: {
|
||||||
}
|
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
||||||
case JEACH_VALUE: {
|
sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
|
||||||
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
break;
|
||||||
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JEACH_TYPE: {
|
|
||||||
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
|
||||||
sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JEACH_ATOM: {
|
|
||||||
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
|
||||||
if( pThis->eType>=JSON_ARRAY ) break;
|
|
||||||
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JEACH_ID: {
|
|
||||||
sqlite3_result_int64(ctx,
|
|
||||||
(sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JEACH_PARENT: {
|
|
||||||
if( p->i>p->iBegin && p->bRecursive ){
|
|
||||||
sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
|
|
||||||
}
|
}
|
||||||
break;
|
case JEACH_ATOM: {
|
||||||
}
|
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
|
||||||
case JEACH_FULLKEY: {
|
if( pThis->eType>=JSON_ARRAY ) break;
|
||||||
JsonString x;
|
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
|
||||||
jsonStringInit(&x, ctx);
|
break;
|
||||||
if( p->bRecursive ){
|
|
||||||
jsonEachComputePath(p, &x, p->i);
|
|
||||||
}else{
|
|
||||||
if( p->zRoot ){
|
|
||||||
jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
|
|
||||||
}else{
|
|
||||||
jsonAppendChar(&x, '$');
|
|
||||||
}
|
|
||||||
if( p->eType==JSON_ARRAY ){
|
|
||||||
jsonPrintf(30, &x, "[%d]", p->iRowid);
|
|
||||||
}else if( p->eType==JSON_OBJECT ){
|
|
||||||
jsonAppendObjectPathElement(&x, pThis);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jsonReturnString(&x);
|
case JEACH_ID: {
|
||||||
break;
|
sqlite3_result_int64(ctx,
|
||||||
}
|
(sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
|
||||||
case JEACH_PATH: {
|
break;
|
||||||
if( p->bRecursive ){
|
}
|
||||||
|
case JEACH_PARENT: {
|
||||||
|
if( p->i>p->iBegin && p->bRecursive ){
|
||||||
|
sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_FULLKEY: {
|
||||||
JsonString x;
|
JsonString x;
|
||||||
jsonStringInit(&x, ctx);
|
jsonStringInit(&x, ctx);
|
||||||
jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
|
if( p->bRecursive ){
|
||||||
|
jsonEachComputePath(p, &x, p->i);
|
||||||
|
}else{
|
||||||
|
if( p->zRoot ){
|
||||||
|
jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
|
||||||
|
}else{
|
||||||
|
jsonAppendChar(&x, '$');
|
||||||
|
}
|
||||||
|
if( p->eType==JSON_ARRAY ){
|
||||||
|
jsonPrintf(30, &x, "[%d]", p->iRowid);
|
||||||
|
}else if( p->eType==JSON_OBJECT ){
|
||||||
|
jsonAppendObjectPathElementOfNode(&x, pThis);
|
||||||
|
}
|
||||||
|
}
|
||||||
jsonReturnString(&x);
|
jsonReturnString(&x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* For json_each() path and root are the same so fall through
|
case JEACH_PATH: {
|
||||||
** into the root case */
|
if( p->bRecursive ){
|
||||||
/* no break */ deliberate_fall_through
|
JsonString x;
|
||||||
}
|
jsonStringInit(&x, ctx);
|
||||||
default: {
|
jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
|
||||||
const char *zRoot = p->zRoot;
|
jsonReturnString(&x);
|
||||||
if( zRoot==0 ) zRoot = "$";
|
break;
|
||||||
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
|
}
|
||||||
break;
|
/* For json_each() path and root are the same so fall through
|
||||||
}
|
** into the root case */
|
||||||
case JEACH_JSON: {
|
/* no break */ deliberate_fall_through
|
||||||
if( p->sParse.isBinary ){
|
}
|
||||||
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
|
default: {
|
||||||
SQLITE_STATIC);
|
const char *zRoot = p->zRoot;
|
||||||
}else{
|
if( zRoot==0 ) zRoot = "$";
|
||||||
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
|
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_JSON: {
|
||||||
|
if( p->sParse.isBinary ){
|
||||||
|
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
/* Blob scan */
|
||||||
|
switch( iColumn ){
|
||||||
|
case JEACH_KEY: {
|
||||||
|
if( p->nParent==0 ) break;
|
||||||
|
if( p->eType==JSONB_OBJECT ){
|
||||||
|
jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
|
||||||
|
}else{
|
||||||
|
assert( p->eType==JSONB_ARRAY );
|
||||||
|
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_VALUE: {
|
||||||
|
u32 i = jsonSkipLabel(p);
|
||||||
|
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_TYPE: {
|
||||||
|
u32 i = jsonSkipLabel(p);
|
||||||
|
u8 eType = eType = p->sParse.aBlob[i] & 0x0f;
|
||||||
|
sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_ATOM: {
|
||||||
|
u32 i;
|
||||||
|
if( p->eType>=JSON_ARRAY ) break;
|
||||||
|
i = jsonSkipLabel(p);
|
||||||
|
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_ID: {
|
||||||
|
sqlite3_result_int64(ctx, (sqlite3_int64)p->i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_PARENT: {
|
||||||
|
if( p->nParent>0 ){
|
||||||
|
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_FULLKEY: {
|
||||||
|
#if 0
|
||||||
|
JsonString x;
|
||||||
|
jsonStringInit(&x, ctx);
|
||||||
|
if( p->bRecursive ){
|
||||||
|
jsonEachComputePath(p, &x, p->i);
|
||||||
|
}else{
|
||||||
|
if( p->zRoot ){
|
||||||
|
jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
|
||||||
|
}else{
|
||||||
|
jsonAppendChar(&x, '$');
|
||||||
|
}
|
||||||
|
if( p->eType==JSON_ARRAY ){
|
||||||
|
jsonPrintf(30, &x, "[%d]", p->iRowid);
|
||||||
|
}else if( p->eType==JSON_OBJECT ){
|
||||||
|
jsonAppendObjectPathElementOfNode(&x, pThis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jsonReturnString(&x);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_PATH: {
|
||||||
|
#if 0
|
||||||
|
if( p->bRecursive ){
|
||||||
|
JsonString x;
|
||||||
|
jsonStringInit(&x, ctx);
|
||||||
|
jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
|
||||||
|
jsonReturnString(&x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* For json_each() path and root are the same so fall through
|
||||||
|
** into the root case */
|
||||||
|
/* no break */ deliberate_fall_through
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
const char *zRoot = p->zRoot;
|
||||||
|
if( zRoot==0 ) zRoot = "$";
|
||||||
|
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case JEACH_JSON: {
|
||||||
|
if( p->sParse.isBinary ){
|
||||||
|
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -5975,16 +6172,28 @@ static int jsonEachFilter(
|
|||||||
UNUSED_PARAMETER(argc);
|
UNUSED_PARAMETER(argc);
|
||||||
jsonEachCursorReset(p);
|
jsonEachCursorReset(p);
|
||||||
if( idxNum==0 ) return SQLITE_OK;
|
if( idxNum==0 ) return SQLITE_OK;
|
||||||
|
memset(&p->sParse, 0, sizeof(p->sParse));
|
||||||
|
p->sParse.nJPRef = 1;
|
||||||
if( jsonFuncArgMightBeBinary(argv[0]) ){
|
if( jsonFuncArgMightBeBinary(argv[0]) ){
|
||||||
z = (const char*)sqlite3_value_blob(argv[0]);
|
u32 i, n, sz;
|
||||||
isBinary = 1;
|
p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
|
||||||
|
p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
|
||||||
|
if( p->sParse.aBlob==0 ){
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
i = p->i = 0;
|
||||||
|
p->iEnd = 0;
|
||||||
|
p->eType = 0;
|
||||||
|
p->nParent = 0;
|
||||||
|
p->sParse.isBinary = 1;
|
||||||
|
n = jsonbPayloadSize(&p->sParse, i, &sz);
|
||||||
|
p->iEnd = i+n+sz;
|
||||||
|
return SQLITE_OK;
|
||||||
}else{
|
}else{
|
||||||
z = (const char*)sqlite3_value_text(argv[0]);
|
z = (const char*)sqlite3_value_text(argv[0]);
|
||||||
isBinary = 0;
|
isBinary = 0;
|
||||||
}
|
}
|
||||||
if( z==0 ) return SQLITE_OK;
|
if( z==0 ) return SQLITE_OK;
|
||||||
memset(&p->sParse, 0, sizeof(p->sParse));
|
|
||||||
p->sParse.nJPRef = 1;
|
|
||||||
if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){
|
if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){
|
||||||
p->sParse.zJson = sqlite3RCStrRef((char*)z);
|
p->sParse.zJson = sqlite3RCStrRef((char*)z);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
Reference in New Issue
Block a user