Index: ext/misc/json.c ================================================================== --- ext/misc/json.c +++ ext/misc/json.c @@ -32,19 +32,19 @@ typedef sqlite3_uint64 u64; typedef unsigned int u32; typedef unsigned char u8; /* Objects */ -typedef struct Json Json; +typedef struct JsonString JsonString; typedef struct JsonNode JsonNode; typedef struct JsonParse JsonParse; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator ** that can be and is used to create strings other than JSON. */ -struct Json { +struct JsonString { sqlite3_context *pCtx; /* Function context - put error messages here */ char *zBuf; /* Append JSON content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ @@ -87,10 +87,11 @@ u8 iVal; /* Replacement value when JNODE_REPLACE */ u32 n; /* Bytes of content, or number of sub-nodes */ union { const char *zJContent; /* Content for INT, REAL, and STRING */ u32 iAppend; /* More terms for ARRAY and OBJECT */ + u32 iKey; /* Key for ARRAY objects in json_tree() */ } u; }; /* A completely parsed JSON string */ @@ -97,56 +98,48 @@ struct JsonParse { u32 nNode; /* Number of slots of aNode[] used */ u32 nAlloc; /* Number of slots of aNode[] allocated */ JsonNode *aNode; /* Array of nodes containing the parse */ const char *zJson; /* Original JSON string */ + u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ }; -/* -** Return the number of consecutive JsonNode slots need to represent -** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and -** OBJECT types, the number might be larger. -** -** Appended elements are not counted. The value returned is the number -** by which the JsonNode counter should increment in order to go to the -** next peer value. -*/ -static u32 jsonSize(JsonNode *pNode){ - return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; -} - -/* Set the Json object to an empty string -*/ -static void jsonZero(Json *p){ +/************************************************************************** +** Utility routines for dealing with JsonString objects +**************************************************************************/ + +/* Set the JsonString object to an empty string +*/ +static void jsonZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; p->bStatic = 1; } -/* Initialize the Json object +/* Initialize the JsonString object */ -static void jsonInit(Json *p, sqlite3_context *pCtx){ +static void jsonInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; p->bErr = 0; jsonZero(p); } -/* Free all allocated memory and reset the Json object back to its +/* Free all allocated memory and reset the JsonString object back to its ** initial state. */ -static void jsonReset(Json *p){ +static void jsonReset(JsonString *p){ if( !p->bStatic ) sqlite3_free(p->zBuf); jsonZero(p); } /* Report an out-of-memory (OOM) condition */ -static void jsonOom(Json *p){ +static void jsonOom(JsonString *p){ if( !p->bErr ){ p->bErr = 1; sqlite3_result_error_nomem(p->pCtx); jsonReset(p); } @@ -153,11 +146,11 @@ } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ -static int jsonGrow(Json *p, u32 N){ +static int jsonGrow(JsonString *p, u32 N){ u64 nTotal = NnAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ if( p->bErr ) return 1; zNew = sqlite3_malloc64(nTotal); @@ -178,49 +171,49 @@ } p->nAlloc = nTotal; return SQLITE_OK; } -/* Append N bytes from zIn onto the end of the Json string. +/* Append N bytes from zIn onto the end of the JsonString string. */ -static void jsonAppendRaw(Json *p, const char *zIn, u32 N){ +static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } #ifdef SQLITE_DEBUG /* Append the zero-terminated string zIn */ -static void jsonAppend(Json *p, const char *zIn){ +static void jsonAppend(JsonString *p, const char *zIn){ jsonAppendRaw(p, zIn, (u32)strlen(zIn)); } #endif /* Append a single character */ -static void jsonAppendChar(Json *p, char c){ +static void jsonAppendChar(JsonString *p, char c){ if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; p->zBuf[p->nUsed++] = c; } /* Append a comma separator to the output buffer, if the previous ** character is not '[' or '{'. */ -static void jsonAppendSeparator(Json *p){ +static void jsonAppendSeparator(JsonString *p){ char c; if( p->nUsed==0 ) return; c = p->zBuf[p->nUsed-1]; if( c!='[' && c!='{' ) jsonAppendChar(p, ','); } -/* Append the N-byte string in zIn to the end of the Json string +/* Append the N-byte string in zIn to the end of the JsonString string ** under construction. Enclose the string in "..." and escape ** any double-quotes or backslash characters contained within the ** string. */ -static void jsonAppendString(Json *p, const char *zIn, u32 N){ +static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 i; if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; p->zBuf[p->nUsed++] = '"'; for(i=0; ibErr==0 ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, SQLITE_UTF8); jsonZero(p); } assert( p->bStatic ); } + +/************************************************************************** +** Utility routines for dealing with JsonNode and JsonParse objects +**************************************************************************/ + +/* +** Return the number of consecutive JsonNode slots need to represent +** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and +** OBJECT types, the number might be larger. +** +** Appended elements are not counted. The value returned is the number +** by which the JsonNode counter should increment in order to go to the +** next peer value. +*/ +static u32 jsonNodeSize(JsonNode *pNode){ + return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; +} + +/* +** Reclaim all memory allocated by a JsonParse object. But do not +** delete the JsonParse object itself. +*/ +static void jsonParseReset(JsonParse *pParse){ + sqlite3_free(pParse->aNode); + pParse->aNode = 0; + pParse->nNode = 0; + pParse->nAlloc = 0; + sqlite3_free(pParse->aUp); + pParse->aUp = 0; +} /* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return ** the number of JsonNode objects that are encoded. */ static void jsonRenderNode( JsonNode *pNode, /* The node to render */ - Json *pOut, /* Write JSON here */ + JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ switch( pNode->eType ){ case JSON_NULL: { jsonAppendRaw(pOut, "null", 4); @@ -330,11 +353,11 @@ } }else{ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); } - j += jsonSize(&pNode[j]); + j += jsonNodeSize(&pNode[j]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; pNode = &pNode[pNode->u.iAppend]; j = 1; } @@ -354,11 +377,11 @@ jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]); }else{ jsonRenderNode(&pNode[j+1], pOut, aReplace); } } - j += 1 + jsonSize(&pNode[j+1]); + j += 1 + jsonNodeSize(&pNode[j+1]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; pNode = &pNode[pNode->u.iAppend]; j = 1; } @@ -476,11 +499,11 @@ } break; } case JSON_ARRAY: case JSON_OBJECT: { - Json s; + JsonString s; jsonInit(&s, pCtx); jsonRenderNode(pNode, &s, aReplace); jsonResult(&s); break; } @@ -674,18 +697,54 @@ if( i>0 ){ while( isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } if( i<0 ){ - sqlite3_free(pParse->aNode); - pParse->aNode = 0; - pParse->nNode = 0; - pParse->nAlloc = 0; + jsonParseReset(pParse); return 1; } return 0; } + +/* Mark node i of pParse as being a child of iParent. Call recursively +** to fill in all the descendants of node i. +*/ +static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ + JsonNode *pNode = &pParse->aNode[i]; + u32 j; + pParse->aUp[i] = iParent; + switch( pNode->eType ){ + case JSON_ARRAY: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ + jsonParseFillInParentage(pParse, i+j, i); + } + break; + } + case JSON_OBJECT: { + for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ + pParse->aUp[i+j] = i; + jsonParseFillInParentage(pParse, i+j+1, i); + } + break; + } + default: { + break; + } + } +} + +/* +** Compute the parentage of all nodes in a completed parse. +*/ +static int jsonParseFindParents(JsonParse *pParse){ + u32 *aUp; + assert( pParse->aUp==0 ); + aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); + if( aUp==0 ) return SQLITE_NOMEM; + jsonParseFillInParentage(pParse, 0, 0); + return SQLITE_OK; +} /* forward declaration */ static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*); /* @@ -728,11 +787,11 @@ && strncmp(&pRoot[j].u.zJContent[1],zKey,nKey)==0 ){ return jsonLookup(pParse, iRoot+j+1, &zPath[i], pApnd); } j++; - j += jsonSize(&pRoot[j]); + j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; @@ -757,11 +816,11 @@ if( zPath[0]!=']' ) return 0; zPath++; j = 1; for(;;){ while( i>0 && j<=pRoot->n ){ - j += jsonSize(&pRoot[j]); + j += jsonNodeSize(&pRoot[j]); i--; } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; @@ -818,12 +877,12 @@ static void jsonParseFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - Json s; /* Output string - not real JSON */ - JsonParse x; /* The parse */ + JsonString s; /* Output string - not real JSON */ + JsonParse x; /* The parse */ u32 i; char zBuf[100]; assert( argc==1 ); if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return; @@ -836,11 +895,11 @@ jsonAppendRaw(&s, " text: ", 10); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); jsonAppendRaw(&s, "\n", 1); } } - sqlite3_free(x.aNode); + jsonParseReset(&x); jsonResult(&s); } /* ** The json_test1(JSON) function parses and rebuilds the JSON string. @@ -851,11 +910,11 @@ sqlite3_value **argv ){ JsonParse x; /* The parse */ if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return; jsonReturn(x.aNode, context, 0); - sqlite3_free(x.aNode); + jsonParseReset(&x); } /* ** The json_nodecount(JSON) function returns the number of nodes in the ** input JSON string. @@ -866,11 +925,11 @@ sqlite3_value **argv ){ JsonParse x; /* The parse */ if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return; sqlite3_result_int64(context, x.nNode); - sqlite3_free(x.aNode); + jsonParseReset(&x); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** SQL function implementations @@ -885,11 +944,11 @@ sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; - Json jx; + JsonString jx; jsonInit(&jx, context); jsonAppendChar(&jx, '['); for(i=0; ieType==JSON_ARRAY ){ assert( (pNode->jnFlags & JNODE_APPEND)==0 ); for(i=1; i<=pNode->n; n++){ - i += jsonSize(&pNode[i]); + i += jsonNodeSize(&pNode[i]); } } } - sqlite3_free(x.aNode); + jsonParseReset(&x); } sqlite3_result_int64(context, n); } /* @@ -963,11 +1022,11 @@ if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return; pNode = jsonLookup(&x, 0, zPath, 0); if( pNode ){ jsonReturn(pNode, context, 0); } - sqlite3_free(x.aNode); + jsonParseReset(&x); } /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON ** object that contains all name/value given in arguments. Or if any name @@ -977,11 +1036,11 @@ sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; - Json jx; + JsonString jx; const char *z; u32 n; if( argc&1 ){ sqlite3_result_error(context, "json_object() requires an even number " @@ -1037,11 +1096,11 @@ } if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ jsonReturn(x.aNode, context, 0); } } - sqlite3_free(x.aNode); + jsonParseReset(&x); } /* ** json_replace(JSON, PATH, VALUE, ...) ** @@ -1080,12 +1139,13 @@ sqlite3_result_value(context, argv[x.aNode[0].iVal]); }else{ jsonReturn(x.aNode, context, argv); } } - sqlite3_free(x.aNode); + jsonParseReset(&x); } + /* ** json_set(JSON, PATH, VALUE, ...) ** ** Set the value at PATH to VALUE. Create the PATH if it does not already ** exist. Overwrite existing values that do exist. @@ -1131,11 +1191,11 @@ sqlite3_result_value(context, argv[x.aNode[0].iVal]); }else{ jsonReturn(x.aNode, context, argv); } } - sqlite3_free(x.aNode); + jsonParseReset(&x); } /* ** json_type(JSON) ** json_type(JSON, PATH) @@ -1163,26 +1223,27 @@ if( x.nNode ){ JsonNode *pNode = x.aNode; if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0); sqlite3_result_text(context, jsonType[pNode->eType], -1, SQLITE_STATIC); } - sqlite3_free(x.aNode); + jsonParseReset(&x); } /**************************************************************************** ** The json_each virtual table ****************************************************************************/ typedef struct JsonEachCursor JsonEachCursor; struct JsonEachCursor { sqlite3_vtab_cursor base; /* Base class - must be first */ - u32 iRowid; /* The rowid */ - u32 i; /* Index in sParse.aNode[] of current row */ - u32 iEnd; /* EOF when i equals or exceeds this value */ - u8 eType; /* Type of top-level element */ - char *zJson; /* Input json */ - char *zPath; /* Path by which to filter zJson */ - JsonParse sParse; /* The input json */ + u32 iRowid; /* The rowid */ + u32 i; /* Index in sParse.aNode[] of current row */ + u32 iEnd; /* EOF when i equals or exceeds this value */ + u8 eType; /* Type of top-level element */ + u8 bRecursive; /* True for json_tree(). False for json_each() */ + char *zJson; /* Input JSON */ + char *zPath; /* Path by which to filter zJson */ + JsonParse sParse; /* Parse of the input JSON */ }; /* Constructor for the json_each virtual table */ static int jsonEachConnect( sqlite3 *db, @@ -1190,51 +1251,68 @@ int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; - pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; + int rc; /* Column numbers */ #define JEACH_KEY 0 #define JEACH_VALUE 1 -#define JEACH_JSON 2 -#define JEACH_PATH 3 +#define JEACH_TYPE 2 +#define JEACH_ATOM 3 +#define JEACH_ID 4 +#define JEACH_PARENT 5 +#define JEACH_JSON 6 +#define JEACH_PATH 7 - sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,json hidden,path hidden)"); - memset(pNew, 0, sizeof(*pNew)); - return SQLITE_OK; + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(key,value,type,atom,id,parent,json hidden,path hidden)"); + if( rc==SQLITE_OK ){ + pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } -/* constructor for a JsonEachCursor object. */ -static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ +/* constructor for a JsonEachCursor object for json_each(). */ +static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ JsonEachCursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } + +/* constructor for a JsonEachCursor object for json_tree(). */ +static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + int rc = jsonEachOpenEach(p, ppCursor); + if( rc==SQLITE_OK ){ + JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; + pCur->bRecursive = 1; + } + return rc; +} /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ sqlite3_free(p->zJson); sqlite3_free(p->zPath); - sqlite3_free(p->sParse.aNode); + jsonParseReset(&p->sParse); p->iRowid = 0; p->i = 0; p->iEnd = 0; p->eType = 0; - memset(&p->sParse, 0, sizeof(p->sParse)); p->zJson = 0; p->zPath = 0; } /* Destructor for a jsonEachCursor object */ @@ -1250,22 +1328,43 @@ static int jsonEachEof(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; return p->i >= p->iEnd; } -/* Advance the cursor to the next top-level element of the current -** JSON string */ -static int jsonEachNext(sqlite3_vtab_cursor *cur){ +/* Advance the cursor to the next element for json_tree() */ +static int jsonEachNextTree(sqlite3_vtab_cursor *cur){ + JsonEachCursor *p = (JsonEachCursor*)cur; + if( p->i==0 ){ + p->i = 1; + }else if( p->sParse.aNode[p->sParse.aUp[p->i]].eType==JSON_OBJECT ){ + p->i += 2; + }else{ + p->i++; + } + p->iRowid++; + if( p->isParse.nNode ){ + JsonNode *pUp = &p->sParse.aNode[p->sParse.aUp[p->i]]; + p->eType = pUp->eType; + if( pUp->eType==JSON_ARRAY ) pUp->u.iKey++; + if( p->sParse.aNode[p->i].eType==JSON_ARRAY ){ + p->sParse.aNode[p->i].u.iKey = 0; + } + } + return SQLITE_OK; +} + +/* Advance the cursor to the next element for json_each() */ +static int jsonEachNextEach(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; switch( p->eType ){ case JSON_ARRAY: { - p->i += jsonSize(&p->sParse.aNode[p->i]); + p->i += jsonNodeSize(&p->sParse.aNode[p->i]); p->iRowid++; break; } case JSON_OBJECT: { - p->i += 1 + jsonSize(&p->sParse.aNode[p->i+1]); + p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); p->iRowid++; break; } default: { p->i = p->iEnd; @@ -1280,24 +1379,50 @@ sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; + JsonNode *pThis = &p->sParse.aNode[p->i]; switch( i ){ case JEACH_KEY: { if( p->eType==JSON_OBJECT ){ - jsonReturn(&p->sParse.aNode[p->i], ctx, 0); - }else{ - sqlite3_result_int64(ctx, p->iRowid); + jsonReturn(pThis, ctx, 0); + }else if( p->eType==JSON_ARRAY ){ + u32 iKey; + if( p->bRecursive ){ + if( p->iRowid==0 ) break; + iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey - 1; + }else{ + iKey = p->iRowid; + } + sqlite3_result_int64(ctx, iKey); } break; } case JEACH_VALUE: { - if( p->eType==JSON_OBJECT ){ - jsonReturn(&p->sParse.aNode[p->i+1], ctx, 0); - }else{ - jsonReturn(&p->sParse.aNode[p->i], ctx, 0); + if( p->eType==JSON_OBJECT ) pThis++; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_TYPE: { + if( p->eType==JSON_OBJECT ) pThis++; + sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); + break; + } + case JEACH_ATOM: { + if( p->eType==JSON_OBJECT ) pThis++; + if( pThis->eType>=JSON_ARRAY ) break; + jsonReturn(pThis, ctx, 0); + break; + } + case JEACH_ID: { + sqlite3_result_int64(ctx, p->i + (p->eType==JSON_OBJECT)); + break; + } + case JEACH_PARENT: { + if( p->i>0 && p->bRecursive ){ + sqlite3_result_int64(ctx, p->sParse.aUp[p->i]); } break; } case JEACH_PATH: { const char *zPath = p->zPath; @@ -1304,10 +1429,11 @@ if( zPath==0 ) zPath = "$"; sqlite3_result_text(ctx, zPath, -1, SQLITE_STATIC); break; } default: { + assert( i==JEACH_JSON ); sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; } } return SQLITE_OK; @@ -1343,13 +1469,13 @@ default: /* no-op */ break; } } if( jsonIdx<0 ){ pIdxInfo->idxNum = 0; - pIdxInfo->estimatedCost = (double)2000000000; + pIdxInfo->estimatedCost = 1e99; }else{ - pIdxInfo->estimatedCost = (double)1; + pIdxInfo->estimatedCost = 1.0; pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; if( pathIdx<0 ){ pIdxInfo->idxNum = 1; }else{ @@ -1382,11 +1508,13 @@ } n = sqlite3_value_bytes(argv[0]); p->zJson = sqlite3_malloc( n+1 ); if( p->zJson==0 ) return SQLITE_NOMEM; memcpy(p->zJson, z, n+1); - if( jsonParse(&p->sParse, p->zJson) ){ + if( jsonParse(&p->sParse, p->zJson) + || (p->bRecursive && jsonParseFindParents(&p->sParse)) + ){ jsonEachCursorReset(p); }else{ JsonNode *pNode; if( idxNum==3 ){ n = sqlite3_value_bytes(argv[1]); @@ -1419,14 +1547,38 @@ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ - jsonEachOpen, /* xOpen - open a cursor */ + jsonEachOpenEach, /* xOpen - open a cursor */ + jsonEachClose, /* xClose - close a cursor */ + jsonEachFilter, /* xFilter - configure scan constraints */ + jsonEachNextEach, /* xNext - advance a cursor */ + jsonEachEof, /* xEof - check for end of scan */ + jsonEachColumn, /* xColumn - read data */ + jsonEachRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ +}; + +/* The methods of the json_tree virtual table. */ +static sqlite3_module jsonTreeModule = { + 0, /* iVersion */ + 0, /* xCreate */ + jsonEachConnect, /* xConnect */ + jsonEachBestIndex, /* xBestIndex */ + jsonEachDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + jsonEachOpenTree, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ - jsonEachNext, /* xNext - advance a cursor */ + jsonEachNextTree, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ @@ -1435,10 +1587,15 @@ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; +/**************************************************************************** +** The following routine is the only publically visible identifier in this +** file. Call the following routine in order to register the various SQL +** functions and the virtual table implemented by this file. +****************************************************************************/ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_json_init( @@ -1471,18 +1628,25 @@ { "json_parse", 1, 0, jsonParseFunc }, { "json_test1", 1, 0, jsonTest1Func }, { "json_nodecount", 1, 0, jsonNodeCountFunc }, #endif }; + static const struct { + const char *zName; + sqlite3_module *pModule; + } aMod[] = { + { "json_each", &jsonEachModule }, + { "json_tree", &jsonTreeModule }, + }; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ for(i=0; i