diff options
author | drh <drh@noemail.net> | 2015-09-11 00:06:41 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2015-09-11 00:06:41 +0000 |
commit | f5ddb9c214b5e6237e9bfb878aa21cfd2ef129fc (patch) | |
tree | f3f2f995669f51045636d3a368709c4b403bf413 /ext/misc/json1.c | |
parent | cf94f179647fd7573f58ad40bbf5603a77035a73 (diff) | |
download | sqlite-f5ddb9c214b5e6237e9bfb878aa21cfd2ef129fc.tar.gz sqlite-f5ddb9c214b5e6237e9bfb878aa21cfd2ef129fc.zip |
Take out the goofy '$$' path syntax. Instead, use subtypes to communicate when
a string is JSON. Add the json() function that validates and minifies the
JSON and sets the appropriate subtype.
FossilOrigin-Name: 8a80d6459e246ec1b38325e1cbd1e862157138b3
Diffstat (limited to 'ext/misc/json1.c')
-rw-r--r-- | ext/misc/json1.c | 89 |
1 files changed, 28 insertions, 61 deletions
diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 755d035c3..a217ce80b 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -68,6 +68,9 @@ struct JsonString { #define JSON_ARRAY 6 #define JSON_OBJECT 7 +/* The "subtype" set for JSON values */ +#define JSON_SUBTYPE 74 /* Ascii for "J" */ + /* ** Names of the various JSON types: */ @@ -82,8 +85,7 @@ static const char * const jsonType[] = { #define JNODE_REMOVE 0x04 /* Do not output */ #define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */ #define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ -#define JNODE_JSON 0x20 /* Treat REPLACE as JSON text */ -#define JNODE_LABEL 0x40 /* Is a label of an object */ +#define JNODE_LABEL 0x20 /* Is a label of an object */ /* A single node of parsed JSON @@ -243,8 +245,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ */ static void jsonAppendValue( JsonString *p, /* Append to this JSON string */ - sqlite3_value *pValue, /* Value to append */ - u8 textIsJson /* Try to treat text values as JSON */ + sqlite3_value *pValue /* Value to append */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { @@ -261,7 +262,7 @@ static void jsonAppendValue( case SQLITE_TEXT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); - if( textIsJson ){ + if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ jsonAppendRaw(p, z, n); }else{ jsonAppendString(p, z, n); @@ -365,8 +366,7 @@ static void jsonRenderNode( if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){ if( pNode[j].jnFlags & JNODE_REPLACE ){ jsonAppendSeparator(pOut); - jsonAppendValue(pOut, aReplace[pNode[j].iVal], - (pNode[j].jnFlags & JNODE_JSON)!=0); + jsonAppendValue(pOut, aReplace[pNode[j].iVal]); } }else{ jsonAppendSeparator(pOut); @@ -391,8 +391,7 @@ static void jsonRenderNode( jsonRenderNode(&pNode[j], pOut, aReplace); jsonAppendChar(pOut, ':'); if( pNode[j+1].jnFlags & JNODE_REPLACE ){ - jsonAppendValue(pOut, aReplace[pNode[j+1].iVal], - (pNode[j+1].jnFlags & JNODE_JSON)!=0); + jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]); }else{ jsonRenderNode(&pNode[j+1], pOut, aReplace); } @@ -421,6 +420,7 @@ static void jsonReturnJson( jsonInit(&s, pCtx); jsonRenderNode(pNode, &s, aReplace); jsonResult(&s); + sqlite3_result_subtype(pCtx, JSON_SUBTYPE); } /* @@ -951,21 +951,15 @@ static char *jsonPathSyntaxError(const char *zErr){ ** ** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if ** nodes are appended. -** -** If the path starts with $$ then set *pFlags to JNODE_REPLACE|JNODE_JSON -** as a single to the caller that the input text to be inserted should be -** interpreted as JSON rather than as ordinary text. */ static JsonNode *jsonLookup( JsonParse *pParse, /* The JSON to search */ const char *zPath, /* The path to search */ int *pApnd, /* Append nodes to complete path if not NULL */ - sqlite3_context *pCtx, /* Report errors here, if not NULL */ - u8 *pFlags /* Write JNODE_REPLACE or _REPLACE|_JSON here */ + sqlite3_context *pCtx /* Report errors here, if not NULL */ ){ const char *zErr = 0; JsonNode *pNode = 0; - u8 fg = JNODE_REPLACE; if( zPath==0 ) return 0; if( zPath[0]!='$' ){ @@ -973,15 +967,6 @@ static JsonNode *jsonLookup( goto lookup_err; } zPath++; - if( zPath[0]=='$' ){ - if( pFlags==0 ){ - zErr = zPath; - goto lookup_err; - } - zPath++; - fg = JNODE_REPLACE|JNODE_JSON; - } - if( pFlags ) *pFlags = fg; pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); return pNode; @@ -996,7 +981,6 @@ lookup_err: sqlite3_result_error_nomem(pCtx); } } - if( pFlags ) *pFlags = fg; return 0; } @@ -1060,32 +1044,16 @@ static void jsonParseFunc( } /* -** The json_test1(JSON) function parses and rebuilds the JSON string. +** The json_test1(JSON) function return true (1) if the input is JSON +** text generated by another json function. It returns (0) if the input +** is not known to be JSON. */ static void jsonTest1Func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - jsonReturnJson(x.aNode, ctx, 0); - jsonParseReset(&x); -} - -/* -** The json_nodecount(JSON) function returns the number of nodes in the -** input JSON string. -*/ -static void jsonNodeCountFunc( - sqlite3_context *ctx, - int argc, - sqlite3_value **argv -){ - JsonParse x; /* The parse */ - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - sqlite3_result_int64(ctx, (sqlite3_int64)x.nNode); - jsonParseReset(&x); + sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ @@ -1110,10 +1078,11 @@ static void jsonArrayFunc( jsonAppendChar(&jx, '['); for(i=0; i<argc; i++){ jsonAppendSeparator(&jx); - jsonAppendValue(&jx, argv[i], 0); + jsonAppendValue(&jx, argv[i]); } jsonAppendChar(&jx, ']'); jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); } @@ -1138,7 +1107,7 @@ static void jsonArrayLengthFunc( JsonNode *pNode; if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx, 0); + pNode = jsonLookup(&x, zPath, 0, ctx); }else{ pNode = x.aNode; } @@ -1180,7 +1149,7 @@ static void jsonExtractFunc( jsonAppendChar(&jx, '['); for(i=1; i<argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx, 0); + pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) break; if( argc>2 ){ jsonAppendSeparator(&jx); @@ -1196,6 +1165,7 @@ static void jsonExtractFunc( if( argc>2 && i==argc ){ jsonAppendChar(&jx, ']'); jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); } jsonReset(&jx); jsonParseReset(&x); @@ -1234,10 +1204,11 @@ static void jsonObjectFunc( n = (u32)sqlite3_value_bytes(argv[i]); jsonAppendString(&jx, z, n); jsonAppendChar(&jx, ':'); - jsonAppendValue(&jx, argv[i+1], 0); + jsonAppendValue(&jx, argv[i+1]); } jsonAppendChar(&jx, '}'); jsonResult(&jx); + sqlite3_result_subtype(ctx, JSON_SUBTYPE); } @@ -1263,7 +1234,7 @@ static void jsonRemoveFunc( for(i=1; i<(u32)argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); if( zPath==0 ) goto remove_done; - pNode = jsonLookup(&x, zPath, 0, ctx, 0); + pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto remove_done; if( pNode ) pNode->jnFlags |= JNODE_REMOVE; } @@ -1299,13 +1270,11 @@ static void jsonReplaceFunc( if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ for(i=1; i<(u32)argc; i+=2){ - u8 jnFlags = JNODE_REPLACE; zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx, &jnFlags); + pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto replace_err; if( pNode ){ - pNode->jnFlags &= ~JNODE_JSON; - pNode->jnFlags |= jnFlags; + pNode->jnFlags |= JNODE_REPLACE; pNode->iVal = i+1; } } @@ -1351,18 +1320,16 @@ static void jsonSetFunc( if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ for(i=1; i<(u32)argc; i+=2){ - u8 jnFlags = JNODE_REPLACE; zPath = (const char*)sqlite3_value_text(argv[i]); bApnd = 0; - pNode = jsonLookup(&x, zPath, &bApnd, ctx, &jnFlags); + pNode = jsonLookup(&x, zPath, &bApnd, ctx); if( x.oom ){ sqlite3_result_error_nomem(ctx); goto jsonSetDone; }else if( x.nErr ){ goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ - pNode->jnFlags &= ~JNODE_JSON; - pNode->jnFlags |= jnFlags; + pNode->jnFlags |= JNODE_REPLACE; pNode->iVal = i+1; } } @@ -1396,7 +1363,7 @@ static void jsonTypeFunc( JsonNode *pNode; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx, 0); + pNode = jsonLookup(&x, zPath, 0, ctx); }else{ pNode = x.aNode; } @@ -1917,6 +1884,7 @@ int sqlite3_json_init( int flag; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { + { "json", 1, 0, jsonRemoveFunc }, { "json_array", -1, 0, jsonArrayFunc }, { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, @@ -1934,7 +1902,6 @@ int sqlite3_json_init( /* DEBUG and TESTING functions */ { "json_parse", 1, 0, jsonParseFunc }, { "json_test1", 1, 0, jsonTest1Func }, - { "json_nodecount", 1, 0, jsonNodeCountFunc }, #endif }; #ifndef SQLITE_OMIT_VIRTUALTABLE |