From: drh Date: Thu, 10 Sep 2015 03:29:11 +0000 (+0000) Subject: Fix the json_tree() scan for the case when a path is supplied. Add new X-Git-Tag: version-3.9.0~128 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=852944eb9b750445956c156c89e54dcbdc843629;p=thirdparty%2Fsqlite.git Fix the json_tree() scan for the case when a path is supplied. Add new json1 test cases. FossilOrigin-Name: 6adc7de76acee6cfb5ff761739e7a8de7b5bf4b2 --- diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 5df7551dec..d51d69e1ee 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -83,6 +83,7 @@ static const char * const jsonType[] = { #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 */ /* A single node of parsed JSON @@ -583,6 +584,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ u32 j; int iThis; int x; + JsonNode *pNode; while( isspace(pParse->zJson[i]) ){ i++; } if( (c = pParse->zJson[i])==0 ) return 0; if( c=='{' ){ @@ -597,7 +599,9 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ return -1; } if( pParse->oom ) return -1; - if( pParse->aNode[pParse->nNode-1].eType!=JSON_STRING ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; j = x; while( isspace(pParse->zJson[j]) ){ j++; } if( pParse->zJson[j]!=':' ) return -1; @@ -1036,13 +1040,20 @@ static void jsonParseFunc( jsonParseFindParents(&x); jsonInit(&s, ctx); for(i=0; ibRecursive ){ - if( p->i==0 ){ - p->i = 1; - }else{ - u32 iUp = p->sParse.aUp[p->i]; - JsonNode *pUp = &p->sParse.aNode[iUp]; - p->i++; - if( pUp->eType==JSON_OBJECT && (pUp->n + iUp >= p->i) ) p->i++; - } + if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; + p->i++; p->iRowid++; - if( p->isParse.nNode ){ + if( p->iiEnd ){ u32 iUp = p->sParse.aUp[p->i]; JsonNode *pUp = &p->sParse.aNode[iUp]; p->eType = pUp->eType; @@ -1597,8 +1603,9 @@ static void jsonEachComputePath( jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); }else{ assert( pUp->eType==JSON_OBJECT ); - if( pNode->eType>=JSON_ARRAY ) pNode--; + if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--; assert( pNode->eType==JSON_STRING ); + assert( pNode->jnFlags & JNODE_LABEL ); jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); } } @@ -1629,27 +1636,28 @@ static int jsonEachColumn( break; } case JEACH_VALUE: { - if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; + if( pThis->jnFlags & JNODE_LABEL ) pThis++; jsonReturn(pThis, ctx, 0); break; } case JEACH_TYPE: { - if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; + if( pThis->jnFlags & JNODE_LABEL ) pThis++; sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { - if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; + if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->eType>=JSON_ARRAY ) break; jsonReturn(pThis, ctx, 0); break; } case JEACH_ID: { - sqlite3_result_int64(ctx, (sqlite3_int64)p->i + (p->eType==JSON_OBJECT)); + sqlite3_result_int64(ctx, + (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); break; } case JEACH_PARENT: { - if( p->i>0 && p->bRecursive ){ + if( p->i>p->iBegin && p->bRecursive ){ sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); } break; @@ -1794,7 +1802,6 @@ static int jsonEachFilter( JsonNode *pNode; if( idxNum==3 ){ const char *zErr = 0; - p->bRecursive = 0; n = sqlite3_value_bytes(argv[1]); p->zPath = sqlite3_malloc64( n+1 ); if( p->zPath==0 ) return SQLITE_NOMEM; @@ -1811,12 +1818,18 @@ static int jsonEachFilter( }else{ pNode = p->sParse.aNode; } - p->i = (int)(pNode - p->sParse.aNode); + p->iBegin = p->i = (int)(pNode - p->sParse.aNode); p->eType = pNode->eType; if( p->eType>=JSON_ARRAY ){ pNode->u.iKey = 0; p->iEnd = p->i + pNode->n + 1; - if( !p->bRecursive ) p->i++; + if( p->bRecursive ){ + if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){ + p->i--; + } + }else{ + p->i++; + } }else{ p->iEnd = p->i+1; } diff --git a/manifest b/manifest index 19012fac78..7b61a44b5a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C No-op\sthe\ssqlite3_memory_alarm()\sinterface\sin\sa\sdifferent\sway,\sthat\sdoes\nnot\sbreak\slegacy\smemory\sbehavior.\s\sThis\sis\sa\sre-do\sof\ncheck-in\s[5d3f5df4da9f40d5]. -D 2015-09-10T01:22:09.178 +C Fix\sthe\sjson_tree()\sscan\sfor\sthe\scase\swhen\sa\spath\sis\ssupplied.\s\sAdd\snew\njson1\stest\scases. +D 2015-09-10T03:29:11.778 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -194,7 +194,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 bd51e8c1e8ce580e6f21493bd8e94ed5aca3d777 +F ext/misc/json1.c 46c2aff110eb8241591cd29267ddb57a8d0ab337 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63 F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc @@ -814,6 +814,7 @@ F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/json101.test 11535d8986184500f4c30cc2f0b154b4ab05cc4e +F test/json102.test ab2ea59639ecf2ad95101015c3357b1ba53ebd98 F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 @@ -1383,7 +1384,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 86146a731d75eb25279c0e072c0bdda593de905d -R 7c5553c63d5721a9d16f1642ebb06bea +P 8250e2a487ee12c9a2dea5603ab60aed51e5dc7b +R c3aaad669751ca08269190cf668389ec U drh -Z 0fce0dbaade5235ccf22a67355771bfc +Z cc385c8c27ee83d7a7141ac119ad0322 diff --git a/manifest.uuid b/manifest.uuid index 5a207b3806..fe04945ac4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8250e2a487ee12c9a2dea5603ab60aed51e5dc7b \ No newline at end of file +6adc7de76acee6cfb5ff761739e7a8de7b5bf4b2 \ No newline at end of file diff --git a/test/json102.test b/test/json102.test new file mode 100644 index 0000000000..4ef1feb083 --- /dev/null +++ b/test/json102.test @@ -0,0 +1,238 @@ +# 2015-08-12 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements tests for JSON SQL functions extension to the +# SQLite library. +# +# This file contains tests automatically generated from the json1 +# documentation. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +load_static_extension db json +do_execsql_test json102-100 { + SELECT json_array(1,2,'3',4); +} {{[1,2,"3",4]}} +do_execsql_test json102-110 { + SELECT json_array('[1,2]'); +} {{["[1,2]"]}} +do_execsql_test json102-120 { + SELECT json_array(1,null,'3','[4,5]','{"six":7.7}'); +} {{[1,null,"3","[4,5]","{\"six\":7.7}"]}} +do_execsql_test json102-130 { + SELECT json_array_length('[1,2,3,4]'); +} {{4}} +do_execsql_test json102-140 { + SELECT json_array_length('{"one":[1,2,3]}'); +} {{0}} +do_execsql_test json102-150 { + SELECT json_array_length('{"one":[1,2,3]}', '$.one'); +} {{3}} +do_execsql_test json102-160 { + SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$'); +} {{{"a":2,"c":[4,5,{"f":7}]}}} +do_execsql_test json102-170 { + SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c'); +} {{[4,5,{"f":7}]}} +do_execsql_test json102-180 { + SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]'); +} {{{"f":7}}} +do_execsql_test json102-190 { + SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f'); +} {{7}} +do_execsql_test json102-200 { + SELECT json_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a'); +} {{[[4,5],2]}} +do_execsql_test json102-210 { + SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x'); +} {{}} +do_execsql_test json102-220 { + SELECT json_insert('{"a":2,"c":4}', '$.a', 99); +} {{{"a":2,"c":4}}} +do_execsql_test json102-230 { + SELECT json_insert('{"a":2,"c":4}', '$.e', 99); +} {{{"a":2,"c":4,"e":99}}} +do_execsql_test json102-240 { + SELECT json_replace('{"a":2,"c":4}', '$.a', 99); +} {{{"a":99,"c":4}}} +do_execsql_test json102-250 { + SELECT json_replace('{"a":2,"c":4}', '$.e', 99); +} {{{"a":2,"c":4}}} +do_execsql_test json102-260 { + SELECT json_set('{"a":2,"c":4}', '$.a', 99); +} {{{"a":99,"c":4}}} +do_execsql_test json102-270 { + SELECT json_set('{"a":2,"c":4}', '$.e', 99); +} {{{"a":2,"c":4,"e":99}}} +do_execsql_test json102-280 { + SELECT json_object('a',2,'c',4); +} {{{"a":2,"c":4}}} +do_execsql_test json102-290 { + SELECT json_object('a',2,'c','{e:5}'); +} {{{"a":2,"c":"{e:5}"}}} +do_execsql_test json102-300 { + SELECT json_remove('[0,1,2,3,4]','$[2]'); +} {{[0,1,3,4]}} +do_execsql_test json102-310 { + SELECT json_remove('[0,1,2,3,4]','$[2]','$[0]'); +} {{[1,3,4]}} +do_execsql_test json102-320 { + SELECT json_remove('[0,1,2,3,4]','$[0]','$[2]'); +} {{[1,2,4]}} +do_execsql_test json102-330 { + SELECT json_remove('{"x":25,"y":42}'); +} {{{"x":25,"y":42}}} +do_execsql_test json102-340 { + SELECT json_remove('{"x":25,"y":42}','$.z'); +} {{{"x":25,"y":42}}} +do_execsql_test json102-350 { + SELECT json_remove('{"x":25,"y":42}','$.y'); +} {{{"x":25}}} +do_execsql_test json102-360 { + SELECT json_remove('{"x":25,"y":42}','$'); +} {{}} +do_execsql_test json102-370 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}'); +} {{object}} +do_execsql_test json102-380 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$'); +} {{object}} +do_execsql_test json102-390 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a'); +} {{array}} +do_execsql_test json102-400 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]'); +} {{integer}} +do_execsql_test json102-410 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]'); +} {{real}} +do_execsql_test json102-420 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]'); +} {{true}} +do_execsql_test json102-430 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]'); +} {{false}} +do_execsql_test json102-440 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]'); +} {{null}} +do_execsql_test json102-450 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]'); +} {{text}} +do_execsql_test json102-460 { + SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]'); +} {{}} +do_execsql_test json102-470 { + SELECT json_valid('{"x":35}'); +} {{1}} +do_execsql_test json102-480 { + SELECT json_valid('{"x":35'); -- } +} {{0}} + +do_execsql_test json102-500 { + CREATE TABLE user(name,phone); + INSERT INTO user(name,phone) VALUES + ('Alice','["919-555-2345","804-555-3621"]'), + ('Bob','["201-555-8872"]'), + ('Cindy','["704-555-9983"]'), + ('Dave','["336-555-8421","704-555-4321","803-911-4421"]'); + SELECT DISTINCT user.name + FROM user, json_each(user.phone) + WHERE json_each.value LIKE '704-%' + ORDER BY 1; +} {Cindy Dave} + +do_execsql_test json102-510 { + UPDATE user + SET phone=json_extract(phone,'$[0]') + WHERE json_array_length(phone)<2; + SELECT name, substr(phone,1,5) FROM user ORDER BY name; +} {Alice {["919} Bob 201-5 Cindy 704-5 Dave {["336}} +do_execsql_test json102-511 { + SELECT name FROM user WHERE phone LIKE '704-%' + UNION + SELECT user.name + FROM user, json_each(user.phone) + WHERE json_valid(user.phone) + AND json_each.value LIKE '704-%'; +} {Cindy Dave} + +do_execsql_test json102-600 { + CREATE TABLE big(json JSON); + INSERT INTO big(json) VALUES('{ + "id":123, + "stuff":[1,2,3,4], + "partlist":[ + {"uuid":"bb108722-572e-11e5-9320-7f3b63a4ca74"}, + {"uuid":"c690dc14-572e-11e5-95f9-dfc8861fd535"}, + {"subassembly":[ + {"uuid":"6fa5181e-5721-11e5-a04e-57f3d7b32808"} + ]} + ] + }'); + INSERT INTO big(json) VALUES('{ + "id":456, + "stuff":["hello","world","xyzzy"], + "partlist":[ + {"uuid":false}, + {"uuid":"c690dc14-572e-11e5-95f9-dfc8861fd535"} + ] + }'); +} {} +set correct_answer [list \ + 1 {$.id} 123 \ + 1 {$.stuff[0]} 1 \ + 1 {$.stuff[1]} 2 \ + 1 {$.stuff[2]} 3 \ + 1 {$.stuff[3]} 4 \ + 1 {$.partlist[0].uuid} bb108722-572e-11e5-9320-7f3b63a4ca74 \ + 1 {$.partlist[1].uuid} c690dc14-572e-11e5-95f9-dfc8861fd535 \ + 1 {$.partlist[2].subassembly[0].uuid} 6fa5181e-5721-11e5-a04e-57f3d7b32808 \ + 2 {$.id} 456 \ + 2 {$.stuff[0]} hello \ + 2 {$.stuff[1]} world \ + 2 {$.stuff[2]} xyzzy \ + 2 {$.partlist[0].uuid} 0 \ + 2 {$.partlist[1].uuid} c690dc14-572e-11e5-95f9-dfc8861fd535] +do_execsql_test json102-610 { + SELECT big.rowid, fullkey, value + FROM big, json_tree(big.json) + WHERE json_tree.type NOT IN ('object','array') + ORDER BY +big.rowid, +json_tree.id +} $correct_answer +do_execsql_test json102-620 { + SELECT big.rowid, fullkey, atom + FROM big, json_tree(big.json) + WHERE atom IS NOT NULL + ORDER BY +big.rowid, +json_tree.id +} $correct_answer + +do_execsql_test json102-630 { + SELECT DISTINCT json_extract(big.json,'$.id') + FROM big, json_tree(big.json,'$.partlist') + WHERE json_tree.key='uuid' + AND json_tree.value='6fa5181e-5721-11e5-a04e-57f3d7b32808'; +} {123} +do_execsql_test json102-631 { + SELECT DISTINCT json_extract(big.json,'$.id') + FROM big, json_tree(big.json,'$') + WHERE json_tree.key='uuid' + AND json_tree.value='6fa5181e-5721-11e5-a04e-57f3d7b32808'; +} {123} +do_execsql_test json102-632 { + SELECT DISTINCT json_extract(big.json,'$.id') + FROM big, json_tree(big.json) + WHERE json_tree.key='uuid' + AND json_tree.value='6fa5181e-5721-11e5-a04e-57f3d7b32808'; +} {123} + + +finish_test