Add the json_tree() virtual table.

FossilOrigin-Name: 08c36e45f0d3a7b89caf823652d7543b76ac802a
This commit is contained in:
drh
2015-08-21 17:33:11 +00:00
parent a7781dc0bb
commit 505ad2ca41
3 changed files with 263 additions and 99 deletions
+256 -92
View File
@@ -34,7 +34,7 @@ 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;
@@ -42,7 +42,7 @@ typedef struct JsonParse JsonParse;
** 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[] */
@@ -89,6 +89,7 @@ struct JsonNode {
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;
};
@@ -99,44 +100,36 @@ struct JsonParse {
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;
}
/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/
/* Set the Json object to an empty string
/* Set the JsonString object to an empty string
*/
static void jsonZero(Json *p){
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);
}
@@ -144,7 +137,7 @@ static void jsonReset(Json *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);
@@ -155,7 +148,7 @@ static void jsonOom(Json *p){
/* 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 = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
@@ -180,9 +173,9 @@ static int jsonGrow(Json *p, u32 N){
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;
@@ -191,14 +184,14 @@ static void jsonAppendRaw(Json *p, const char *zIn, u32 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;
}
@@ -206,19 +199,19 @@ static void jsonAppendChar(Json *p, char 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++] = '"';
@@ -238,7 +231,7 @@ static void jsonAppendString(Json *p, const char *zIn, u32 N){
** construction.
*/
static void jsonAppendValue(
Json *p, /* Append to this JSON string */
JsonString *p, /* Append to this JSON string */
sqlite3_value *pValue /* Value to append */
){
switch( sqlite3_value_type(pValue) ){
@@ -273,7 +266,7 @@ static void jsonAppendValue(
/* Make the JSON in p the result of the SQL function.
*/
static void jsonResult(Json *p){
static void jsonResult(JsonString *p){
if( p->bErr==0 ){
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
@@ -283,6 +276,36 @@ static void jsonResult(Json *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
@@ -290,7 +313,7 @@ static void jsonResult(Json *p){
*/
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 ){
@@ -332,7 +355,7 @@ static void jsonRenderNode(
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];
@@ -356,7 +379,7 @@ static void jsonRenderNode(
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];
@@ -478,7 +501,7 @@ static void jsonReturn(
}
case JSON_ARRAY:
case JSON_OBJECT: {
Json s;
JsonString s;
jsonInit(&s, pCtx);
jsonRenderNode(pNode, &s, aReplace);
jsonResult(&s);
@@ -676,15 +699,51 @@ static int jsonParse(JsonParse *pParse, const char *zJson){
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*);
@@ -730,7 +789,7 @@ static JsonNode *jsonLookup(
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;
@@ -759,7 +818,7 @@ static JsonNode *jsonLookup(
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;
@@ -820,8 +879,8 @@ static void jsonParseFunc(
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];
@@ -838,7 +897,7 @@ static void jsonParseFunc(
jsonAppendRaw(&s, "\n", 1);
}
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
jsonResult(&s);
}
@@ -853,7 +912,7 @@ static void jsonTest1Func(
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);
}
/*
@@ -868,7 +927,7 @@ static void jsonNodeCountFunc(
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 */
@@ -887,7 +946,7 @@ static void jsonArrayFunc(
sqlite3_value **argv
){
int i;
Json jx;
JsonString jx;
jsonInit(&jx, context);
jsonAppendChar(&jx, '[');
@@ -932,11 +991,11 @@ static void jsonArrayLengthFunc(
if( pNode->eType==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);
}
@@ -965,7 +1024,7 @@ static void jsonExtractFunc(
if( pNode ){
jsonReturn(pNode, context, 0);
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
}
/*
@@ -979,7 +1038,7 @@ static void jsonObjectFunc(
sqlite3_value **argv
){
int i;
Json jx;
JsonString jx;
const char *z;
u32 n;
@@ -1039,7 +1098,7 @@ static void jsonRemoveFunc(
jsonReturn(x.aNode, context, 0);
}
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
}
/*
@@ -1082,8 +1141,9 @@ static void jsonReplaceFunc(
jsonReturn(x.aNode, context, argv);
}
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
}
/*
** json_set(JSON, PATH, VALUE, ...)
**
@@ -1133,7 +1193,7 @@ static void jsonSetFunc(
jsonReturn(x.aNode, context, argv);
}
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
}
/*
@@ -1165,7 +1225,7 @@ static void jsonTypeFunc(
if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0);
sqlite3_result_text(context, jsonType[pNode->eType], -1, SQLITE_STATIC);
}
sqlite3_free(x.aNode);
jsonParseReset(&x);
}
/****************************************************************************
@@ -1174,13 +1234,14 @@ static void jsonTypeFunc(
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 */
@@ -1192,18 +1253,26 @@ static int jsonEachConnect(
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 */
@@ -1212,8 +1281,8 @@ static int jsonEachDisconnect(sqlite3_vtab *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;
@@ -1222,17 +1291,26 @@ static int jsonEachOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
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;
}
@@ -1252,18 +1330,39 @@ static int jsonEachEof(sqlite3_vtab_cursor *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->i<p->sParse.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;
}
@@ -1282,20 +1381,46 @@ static int jsonEachColumn(
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;
}
@@ -1306,6 +1431,7 @@ static int jsonEachColumn(
break;
}
default: {
assert( i==JEACH_JSON );
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
break;
}
@@ -1345,9 +1471,9 @@ static int jsonEachBestIndex(
}
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 ){
@@ -1384,7 +1510,9 @@ static int jsonEachFilter(
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;
@@ -1421,10 +1549,10 @@ static sqlite3_module jsonEachModule = {
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 */
jsonEachNext, /* xNext - advance a cursor */
jsonEachNextEach, /* xNext - advance a cursor */
jsonEachEof, /* xEof - check for end of scan */
jsonEachColumn, /* xColumn - read data */
jsonEachRowid, /* xRowid - read data */
@@ -1437,6 +1565,35 @@ static sqlite3_module jsonEachModule = {
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 */
jsonEachNextTree, /* 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 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)
@@ -1473,6 +1630,13 @@ int sqlite3_json_init(
{ "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<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
@@ -1481,8 +1645,8 @@ int sqlite3_json_init(
(void*)&aFunc[i].flag,
aFunc[i].xFunc, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_module(db, "json_each", &jsonEachModule, 0);
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
}
return rc;
}