]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the json_valid() function to the json1.c extension. Fix various minor
authordrh <drh@noemail.net>
Sat, 22 Aug 2015 19:39:04 +0000 (19:39 +0000)
committerdrh <drh@noemail.net>
Sat, 22 Aug 2015 19:39:04 +0000 (19:39 +0000)
problems in the json1.c extension.

FossilOrigin-Name: 380a97345b446214843a63ccc017d49a52d884da

ext/misc/json1.c
manifest
manifest.uuid

index ea456bfeacb7617f22eb02e99d2505b9ee927181..a68ef7469c15ab8284fe707e3122abbbf905dc88 100644 (file)
@@ -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 */
index de7c994cbe781af4a2d1250f8d0b01458cf2a2f4..f08dd2f05ad50bdfec24cd74f1aef04ddda3e2f0 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\scouple\sinstances\sof\sOOM\shandling\sin\sthe\sjson\sextension.
-D 2015-08-22T03:05:54.585
+C Add\sthe\sjson_valid()\sfunction\sto\sthe\sjson1.c\sextension.\s\sFix\svarious\sminor\nproblems\sin\sthe\sjson1.c\sextension.
+D 2015-08-22T19:39:04.060
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in e2218eb228374422969de7b1680eda6864affcef
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -192,7 +192,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
 F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767
 F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
-F ext/misc/json1.c 2eae688e07700b94ed7e03051a90918c6744d0a9
+F ext/misc/json1.c 88273dda16ac505b898be5ba90b29aaabbe37e71
 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
@@ -1378,7 +1378,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 351bc22fa9b5a2e50da3583a882c5aa390bda19f
-R ca8b5b15c77432f02507718e8d7e076f
+P 213a6c5ccbcfe4495d45e3608e99a6398751aeed
+R 71acf7e81664c832e0217a769189f3b7
 U drh
-Z d373dd42adbb610fe45611bf2ca7212e
+Z 942f59d21b0c9aa639cfef239bb85f7f
index 4064ce58f6f607e338071b671c4a1d29c938787f..db562f929c8a6a27af48ef83662ca5575becc97f 100644 (file)
@@ -1 +1 @@
-213a6c5ccbcfe4495d45e3608e99a6398751aeed
\ No newline at end of file
+380a97345b446214843a63ccc017d49a52d884da
\ No newline at end of file