aboutsummaryrefslogtreecommitdiff
path: root/ext/misc/json1.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2015-08-22 19:39:04 +0000
committerdrh <drh@noemail.net>2015-08-22 19:39:04 +0000
commitbc8f092ca10493d59ba619fb5a9fe6a7358e3372 (patch)
tree72f0df9549ba6285491c89a93598e5fb1dbbaf96 /ext/misc/json1.c
parentbe9474ee05fd36fa5925847d9aa6cac9a06f9ad3 (diff)
downloadsqlite-bc8f092ca10493d59ba619fb5a9fe6a7358e3372.tar.gz
sqlite-bc8f092ca10493d59ba619fb5a9fe6a7358e3372.zip
Add the json_valid() function to the json1.c extension. Fix various minor
problems in the json1.c extension. FossilOrigin-Name: 380a97345b446214843a63ccc017d49a52d884da
Diffstat (limited to 'ext/misc/json1.c')
-rw-r--r--ext/misc/json1.c188
1 files changed, 125 insertions, 63 deletions
diff --git a/ext/misc/json1.c b/ext/misc/json1.c
index ea456bfea..a68ef7469 100644
--- a/ext/misc/json1.c
+++ b/ext/misc/json1.c
@@ -573,18 +573,19 @@ static int jsonParseAddNode(
static int jsonParseValue(JsonParse *pParse, u32 i){
char c;
u32 j;
- u32 iThis;
+ int iThis;
int x;
while( isspace(pParse->zJson[i]) ){ i++; }
if( (c = pParse->zJson[i])==0 ) return 0;
if( c=='{' ){
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+ if( iThis<0 ) return -1;
for(j=i+1;;j++){
while( isspace(pParse->zJson[j]) ){ j++; }
x = jsonParseValue(pParse, j);
if( x<0 ){
- if( x==(-2) && pParse->nNode==iThis+1 ) return j+1;
+ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
return -1;
}
if( pParse->oom ) return -1;
@@ -602,16 +603,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( c!='}' ) return -1;
break;
}
- pParse->aNode[iThis].n = pParse->nNode - iThis - 1;
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
return j+1;
}else if( c=='[' ){
/* Parse array */
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+ if( iThis<0 ) return -1;
for(j=i+1;;j++){
while( isspace(pParse->zJson[j]) ){ j++; }
x = jsonParseValue(pParse, j);
if( x<0 ){
- if( x==(-3) && pParse->nNode==iThis+1 ) return j+1;
+ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
return -1;
}
j = x;
@@ -621,7 +623,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( c!=']' ) return -1;
break;
}
- pParse->aNode[iThis].n = pParse->nNode - iThis - 1;
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
return j+1;
}else if( c=='"' ){
/* Parse string */
@@ -701,7 +703,11 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
**
** pParse is uninitialized when this routine is called.
*/
-static int jsonParse(JsonParse *pParse, const char *zJson){
+static int jsonParse(
+ JsonParse *pParse, /* Initialize and fill this JsonParse object */
+ sqlite3_context *pCtx, /* Report errors here */
+ const char *zJson /* Input JSON text to be parsed */
+){
int i;
if( zJson==0 ) return 1;
memset(pParse, 0, sizeof(*pParse));
@@ -712,6 +718,7 @@ static int jsonParse(JsonParse *pParse, const char *zJson){
if( zJson[i] ) i = -1;
}
if( i<0 ){
+ if( pParse->oom && pCtx!=0 ) sqlite3_result_error_nomem(pCtx);
jsonParseReset(pParse);
return 1;
}
@@ -775,7 +782,7 @@ static JsonNode *jsonLookup(
const char *zPath, /* The path to search */
int *pApnd /* Append nodes to complete path if not NULL */
){
- u32 i, j, k, nKey;
+ u32 i, j, nKey;
const char *zKey;
JsonNode *pRoot = &pParse->aNode[iRoot];
if( zPath[0]==0 ) return pRoot;
@@ -810,13 +817,20 @@ static JsonNode *jsonLookup(
j = 1;
}
if( pApnd ){
- k = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- pRoot->u.iAppend = k - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- k = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
- if( !pParse->oom ) pParse->aNode[k].jnFlags |= JNODE_RAW;
+ u32 iStart, iLabel;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
zPath += i;
- return jsonLookupAppend(pParse, zPath, pApnd);
+ pNode = jsonLookupAppend(pParse, zPath, pApnd);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+ }
+ return pNode;
}
}else if( zPath[0]=='[' && isdigit(zPath[1]) ){
if( pRoot->eType!=JSON_ARRAY ) return 0;
@@ -830,9 +844,9 @@ static JsonNode *jsonLookup(
zPath++;
j = 1;
for(;;){
- while( i>0 && j<=pRoot->n ){
+ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
+ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
j += jsonNodeSize(&pRoot[j]);
- i--;
}
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
iRoot += pRoot->u.iAppend;
@@ -843,17 +857,25 @@ static JsonNode *jsonLookup(
return jsonLookup(pParse, iRoot+j, zPath, pApnd);
}
if( i==0 && pApnd ){
- k = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pRoot->u.iAppend = k - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- return jsonLookupAppend(pParse, zPath, pApnd);
+ u32 iStart;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
+ pNode = jsonLookupAppend(pParse, zPath, pApnd);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ }
+ return pNode;
}
}
return 0;
}
/*
-** Append content to pParse that will complete zPath.
+** Append content to pParse that will complete zPath. Return a pointer
+** to the inserted node, or return NULL if the append fails.
*/
static JsonNode *jsonLookupAppend(
JsonParse *pParse, /* Append content to the JSON parse */
@@ -876,6 +898,19 @@ static JsonNode *jsonLookupAppend(
return jsonLookup(pParse, pParse->nNode-1, zPath, pApnd);
}
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ sqlite3_context *pCtx,
+ const char *zFuncName
+){
+ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+}
/****************************************************************************
** SQL functions used for testing and debugging
@@ -888,7 +923,7 @@ static JsonNode *jsonLookupAppend(
** well-formed.
*/
static void jsonParseFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -898,8 +933,8 @@ static void jsonParseFunc(
char zBuf[100];
assert( argc==1 );
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonInit(&s, context);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ jsonInit(&s, ctx);
for(i=0; i<x.nNode; i++){
sqlite3_snprintf(sizeof(zBuf), zBuf, "node %3u: %7s n=%d\n",
i, jsonType[x.aNode[i].eType], x.aNode[i].n);
@@ -918,13 +953,13 @@ static void jsonParseFunc(
** The json_test1(JSON) function parses and rebuilds the JSON string.
*/
static void jsonTest1Func(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x; /* The parse */
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonReturn(x.aNode, context, 0);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ jsonReturn(x.aNode, ctx, 0);
jsonParseReset(&x);
}
@@ -933,13 +968,13 @@ static void jsonTest1Func(
** input JSON string.
*/
static void jsonNodeCountFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x; /* The parse */
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
- sqlite3_result_int64(context, (sqlite3_int64)x.nNode);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ sqlite3_result_int64(ctx, (sqlite3_int64)x.nNode);
jsonParseReset(&x);
}
#endif /* SQLITE_DEBUG */
@@ -954,14 +989,14 @@ static void jsonNodeCountFunc(
** is a BLOB, throw an error.
*/
static void jsonArrayFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
int i;
JsonString jx;
- jsonInit(&jx, context);
+ jsonInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
@@ -980,7 +1015,7 @@ static void jsonArrayFunc(
** Return 0 if the input is not a well-formed JSON array.
*/
static void jsonArrayLengthFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -997,7 +1032,7 @@ static void jsonArrayLengthFunc(
}else{
zPath = 0;
}
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0]))==0 ){
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0]))==0 ){
if( x.nNode ){
JsonNode *pNode = x.aNode;
if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0);
@@ -1010,7 +1045,7 @@ static void jsonArrayLengthFunc(
}
jsonParseReset(&x);
}
- sqlite3_result_int64(context, n);
+ if( !x.oom ) sqlite3_result_int64(ctx, n);
}
/*
@@ -1020,7 +1055,7 @@ static void jsonArrayLengthFunc(
** valid JSON or if there is no PATH element or if PATH is malformed.
*/
static void jsonExtractFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1032,10 +1067,10 @@ static void jsonExtractFunc(
if( zPath==0 ) return;
if( zPath[0]!='$' ) return;
zPath++;
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
pNode = jsonLookup(&x, 0, zPath, 0);
if( pNode ){
- jsonReturn(pNode, context, 0);
+ jsonReturn(pNode, ctx, 0);
}
jsonParseReset(&x);
}
@@ -1046,7 +1081,7 @@ static void jsonExtractFunc(
** is not a string or if any value is a BLOB, throw an error.
*/
static void jsonObjectFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1056,15 +1091,15 @@ static void jsonObjectFunc(
u32 n;
if( argc&1 ){
- sqlite3_result_error(context, "json_object() requires an even number "
+ sqlite3_result_error(ctx, "json_object() requires an even number "
"of arguments", -1);
return;
}
- jsonInit(&jx, context);
+ jsonInit(&jx, ctx);
jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){
if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
- sqlite3_result_error(context, "json_object() labels must be TEXT", -1);
+ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
jsonZero(&jx);
return;
}
@@ -1088,7 +1123,7 @@ static void jsonObjectFunc(
** is returned.
*/
static void jsonRemoveFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1098,7 +1133,7 @@ static void jsonRemoveFunc(
u32 i;
if( argc<1 ) return;
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( x.nNode ){
for(i=1; i<(u32)argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
@@ -1108,7 +1143,7 @@ static void jsonRemoveFunc(
if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
}
if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturn(x.aNode, context, 0);
+ jsonReturn(x.aNode, ctx, 0);
}
}
jsonParseReset(&x);
@@ -1121,7 +1156,7 @@ static void jsonRemoveFunc(
** this routine is a no-op. If JSON is ill-formed, return NULL.
*/
static void jsonReplaceFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1132,11 +1167,10 @@ static void jsonReplaceFunc(
if( argc<1 ) return;
if( (argc&1)==0 ) {
- sqlite3_result_error(context,
- "json_replace() needs an odd number of arguments", -1);
+ jsonWrongNumArgs(ctx, "replace");
return;
}
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( x.nNode ){
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
@@ -1149,9 +1183,9 @@ static void jsonReplaceFunc(
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(context, argv[x.aNode[0].iVal]);
+ sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
}else{
- jsonReturn(x.aNode, context, argv);
+ jsonReturn(x.aNode, ctx, argv);
}
}
jsonParseReset(&x);
@@ -1170,7 +1204,7 @@ static void jsonReplaceFunc(
** routine is a no-op. If JSON is ill-formed, return NULL.
*/
static void jsonSetFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1179,15 +1213,14 @@ static void jsonSetFunc(
const char *zPath;
u32 i;
int bApnd;
- int bIsSet = *(int*)sqlite3_user_data(context);
+ int bIsSet = *(int*)sqlite3_user_data(ctx);
if( argc<1 ) return;
if( (argc&1)==0 ) {
- sqlite3_result_error(context,
- "json_set() needs an odd number of arguments", -1);
+ jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( x.nNode ){
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
@@ -1195,17 +1228,21 @@ static void jsonSetFunc(
if( zPath[0]!='$' ) continue;
bApnd = 0;
pNode = jsonLookup(&x, 0, &zPath[1], &bApnd);
- if( pNode && (bApnd || bIsSet) ){
+ if( x.oom ){
+ sqlite3_result_error_nomem(ctx);
+ goto jsonSetDone;
+ }else if( pNode && (bApnd || bIsSet) ){
pNode->jnFlags |= JNODE_REPLACE;
pNode->iVal = i+1;
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(context, argv[x.aNode[0].iVal]);
+ sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
}else{
- jsonReturn(x.aNode, context, argv);
+ jsonReturn(x.aNode, ctx, argv);
}
}
+jsonSetDone:
jsonParseReset(&x);
}
@@ -1217,7 +1254,7 @@ static void jsonSetFunc(
** input is not a well-formed JSON string.
*/
static void jsonTypeFunc(
- sqlite3_context *context,
+ sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
@@ -1232,13 +1269,37 @@ static void jsonTypeFunc(
}else{
zPath = 0;
}
- if( jsonParse(&x, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
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);
+ if( pNode ){
+ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ }
+ }
+ jsonParseReset(&x);
+}
+
+/*
+** json_valid(JSON)
+**
+** Return 1 if JSON is a valid JSON string. Return 0 otherwise.
+*/
+static void jsonValidFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ int rc = 0;
+
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0]))==0
+ && x.nNode>0
+ ){
+ rc = 1;
}
jsonParseReset(&x);
+ sqlite3_result_int(ctx, rc);
}
/****************************************************************************
@@ -1588,7 +1649,7 @@ static int jsonEachFilter(
p->zJson = sqlite3_malloc64( n+1 );
if( p->zJson==0 ) return SQLITE_NOMEM;
memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, p->zJson)
+ if( jsonParse(&p->sParse, 0, p->zJson)
|| (p->bRecursive && jsonParseFindParents(&p->sParse))
){
jsonEachCursorReset(p);
@@ -1617,7 +1678,7 @@ static int jsonEachFilter(
p->iEnd = p->i+1;
}
}
- return SQLITE_OK;
+ return p->sParse.oom ? SQLITE_NOMEM : SQLITE_OK;
}
/* The methods of the json_each virtual table */
@@ -1707,6 +1768,7 @@ int sqlite3_json_init(
{ "json_set", -1, 1, jsonSetFunc },
{ "json_type", 1, 0, jsonTypeFunc },
{ "json_type", 2, 0, jsonTypeFunc },
+ { "json_valid", 1, 0, jsonValidFunc },
#if SQLITE_DEBUG
/* DEBUG and TESTING functions */