From: drh <> Date: Sat, 8 Jan 2022 15:37:13 +0000 (+0000) Subject: Merge the JSON function enhancements from the json-enhancements branch into X-Git-Tag: version-3.38.0~119^2~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=daefcd9e009616b379eb4c0528a0440dcd0394f8;p=thirdparty%2Fsqlite.git Merge the JSON function enhancements from the json-enhancements branch into json-in-core. FossilOrigin-Name: e116501c2f0e594eb7a3dd804daa943cc508f32ded3078aed21b695ec83bcd4c --- daefcd9e009616b379eb4c0528a0440dcd0394f8 diff --cc manifest index c39afa35cd,38810b62bc..b3ac61a7f5 --- a/manifest +++ b/manifest @@@ -1,11 -1,11 +1,11 @@@ - C An\sattempt\sto\sintegrate\sthe\sJSON\sfunctions\sdirectly\sinto\sthe\sSQLite\score,\nrather\sthan\sholding\sthem\sas\san\sextension. - D 2022-01-06T01:40:09.292 -C Improved\scommenting\sof\schanges\sin\sthe\sjson1.c\sextension. -D 2022-01-08T15:05:53.556 ++C Merge\sthe\sJSON\sfunction\senhancements\sfrom\sthe\sjson-enhancements\sbranch\sinto\njson-in-core. ++D 2022-01-08T15:37:13.201 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 0e91c42a1dd13a569b1fa4f4dfb7d3632f3164a1c05c71341533d67db5b641dd +F Makefile.in fd537743957bfe87997dc5727783d8eec82098921e15eab984d6711cd46f001b F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 - F Makefile.msc 8ba680ec26e6d6f348954e0fee719607688075ef6c242e50e20d28e8ded7cc08 -F Makefile.msc 517f22463b99b56f6c4c81afcf09c7bf3a0289d08f2dadcc0d5322819dbd6017 ++F Makefile.msc 22ce0007874c61c8eb51fc22b84f72af175ce2d7431c242253bdffa39c163da4 F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c F VERSION 392c2f83569705069415a5d98b1c138ec8fe8a56a663a0d94cea019e806537b2 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@@ -34,10 -34,11 +34,11 @@@ F autoconf/tea/win/rules.vc c511f222b80 F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6 F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559 -F configure 56f2a6637cdba53788673ccc229c4f95ab3ab6fe67036e0b1291dc615e531a58 x -F configure.ac c8ba54bac7e73e000acdfef5e394fe21a3876aa09d0f5c07131bf5ac5a525299 +F configure a2877fe63cc821af0df41abe70f1f7c4e97cb7e23a42e0a1402e8a2f55a88aa2 x +F configure.ac 3ef6eeff4387585bfcab76b0c3f6e15a0618587bb90245dd5d44e4378141bb35 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd + F doc/json-enhancements.md b026346e18a18a90d84dbda457e3127282468ad26baaefc005a1656429fa4232 F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a @@@ -494,9 -496,9 +495,9 @@@ F src/btree.c 0e9f84f974e970fb373c15caa F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 F src/build.c 6e16f7b539bfc55149a039bf0cda26b089640339df6147070b072df2d1c4f771 --F src/callback.c 106b585da1edd57d75fa579d823a5218e0bf37f191dbf7417eeb4a8a9a267dbc ++F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1 +F src/ctime.c b09ce320b78718d5e0c4a7a59b8705abe8ee4683d9fa4b33768fe347e1b2a42a F src/date.c ab8e01d928f201f5dee0bc6d54d6702fdcec96dff4d58c387447671f6a46d191 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d @@@ -511,10 -513,9 +512,10 @@@ F src/hash.h 3340ab6e1d13e725571d7cee6d F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743 - F src/json.c 973b36a733cc5d3c8347bbdb3479c1124c0916ee7416341d0126895d055d2447 w ext/misc/json1.c ++F src/json.c 726f1901ecc66bc359d785c268e70c2f10fcec22b212613b00d7da5aa561d462 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d -F src/main.c aa24539f6c26460543d51027ea14b79cad35e34bc9d4907bc349b52b71066644 +F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960 F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@@ -1937,11 -1938,8 +1938,8 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 - P b6a82f3c3b9d89fdf628c7f117b6a4a64383a36c84fe84d47c80e845c9bd8a4f - R 512e6db3c5e4ab4d0c8ece9f791ebefa - T *branch * json-in-core - T *sym-json-in-core * - T -sym-trunk * -P 18160985ea6b2bbf27de25e0f4f3a1ebcdb079a36af039fc06e37a834e49e772 -R ea25b8b6843a230f65190e794ee89370 ++P 583b47d865fb8d2c9ae4d3a4e70356a8a758978efb0a282f6b19775bf41fb748 4d81425e1bf2cff6fa961d0a7936b5f62d3f8ffe9bffea89c1e8b8ddf8fad6f4 ++R 9de2cc0789b4af5e569fa6f6937afbf5 U drh - Z a41c104f7d21d7e5237fb8ae1a000e0b -Z 72ca0ba8118c37c05f41d020549c1f4e ++Z 5d4090391a2a7b92e27e5b55336ae1bf # Remove this line to create a well-formed Fossil manifest. diff --cc manifest.uuid index 8d5afef0f4,dc1aa1ea0e..3d3e816e87 --- a/manifest.uuid +++ b/manifest.uuid @@@ -1,1 -1,1 +1,1 @@@ - 583b47d865fb8d2c9ae4d3a4e70356a8a758978efb0a282f6b19775bf41fb748 -4d81425e1bf2cff6fa961d0a7936b5f62d3f8ffe9bffea89c1e8b8ddf8fad6f4 ++e116501c2f0e594eb7a3dd804daa943cc508f32ded3078aed21b695ec83bcd4c diff --cc src/callback.c index 936c374abd,936c374abd..7d8f9dcbce --- a/src/callback.c +++ b/src/callback.c @@@ -358,7 -358,7 +358,6 @@@ void sqlite3InsertBuiltinFuncs const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); int h = SQLITE_FUNC_HASH(zName[0], nName); -- assert( zName[0]>='a' && zName[0]<='z' ); assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN ); pOther = sqlite3FunctionSearch(h, zName); if( pOther ){ diff --cc src/json.c index 5f39902c0e,26f08e9168..aad4507767 --- a/src/json.c +++ b/src/json.c @@@ -1518,19 -1628,61 +1549,61 @@@ static void jsonExtractFunc JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; - int flags = *(int*)sqlite3_user_data(ctx); ++ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); JsonString jx; - int i; if( argc<2 ) return; - p = jsonParseCached(ctx, argv, ctx); - if( p==0 ) return; - jsonInit(&jx, ctx); - jsonAppendChar(&jx, '['); - for(i=1; inErr ) break; - if( argc>2 ){ + p = jsonParseCached(ctx, argv, (flags & JSON_NULLERR)!=0 ? 0 : ctx); + if( p==0 ){ + /* If the form is "json_nextract(IN,'$')" and IN is not well-formed JSON, + ** then return IN as a quoted JSON string. */ + if( (flags & JSON_NULLERR)!=0 + && argc==2 + && (zPath = (const char*)sqlite3_value_text(argv[1]))!=0 + && zPath[0]=='$' && zPath[1]==0 + ){ + jsonQuoteFunc(ctx, argc, argv); + } + return; + } + if( argc==2 ){ + /* With a single PATH argument, the return is the unquoted SQL value */ + zPath = (const char*)sqlite3_value_text(argv[1]); + if( zPath && zPath[0]!='$' && zPath[0]!=0 && (flags & JSON_ABPATH)!=0 ){ + /* The -> and ->> operators accept abbreviated PATH arguments. This + ** is mostly for compatibility with PostgreSQL, but also for convenience. + ** + ** NUMBER ==> $[NUMBER] // PG compatible + ** LABEL ==> $.LABEL // PG compatible + ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience + */ + jsonInit(&jx, ctx); - if( safe_isdigit(zPath[0]) ){ ++ if( sqlite3Isdigit(zPath[0]) ){ + jsonAppendRaw(&jx, "$[", 2); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendRaw(&jx, "]", 2); + }else{ + jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='[')); + jsonAppendRaw(&jx, zPath, (int)strlen(zPath)); + jsonAppendChar(&jx, 0); + } + pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx); + jsonReset(&jx); + }else{ + pNode = jsonLookup(p, zPath, 0, ctx); + } + if( p->nErr ) return; + if( pNode ) jsonReturn(pNode, ctx, 0); + }else{ + /* Two or more PATH arguments results in a JSON array with each + ** element of the array being the value selected by one of the PATHs */ + int i; + jsonInit(&jx, ctx); + jsonAppendChar(&jx, '['); + for(i=1; inErr ) break; jsonAppendSeparator(&jx); if( pNode ){ jsonRenderNode(pNode, &jx, 0); @@@ -1853,7 -2007,7 +1928,7 @@@ static void jsonTypeFunc const char *zPath; JsonNode *pNode; - p = jsonParseCached(ctx, argv, ctx); - p = jsonParseCached(ctx, argv, *(int*)sqlite3_user_data(ctx) ? 0 : ctx); ++ p = jsonParseCached(ctx, argv, sqlite3_user_data(ctx)!=0 ? 0 : ctx); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); @@@ -2549,53 -2703,64 +2624,57 @@@ static sqlite3_module jsonTreeModule = 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ +#endif /* !defined(SQLITE_OMIT_JSON) */ -/**************************************************************************** -** The following routines are the only publically visible identifiers in this -** file. Call the following routines in order to register the various SQL -** functions and the virtual table implemented by this file. -****************************************************************************/ - -int sqlite3Json1Init(sqlite3 *db){ - int rc = SQLITE_OK; - unsigned int i; - static const struct { - const char *zName; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - int nArg; - int flag; - } aFunc[] = { - { "json", jsonRemoveFunc, 1, 0 }, - { "json_array", jsonArrayFunc, -1, 0 }, - { "json_array_length", jsonArrayLengthFunc, 1, 0 }, - { "json_array_length", jsonArrayLengthFunc, 2, 0 }, - { "json_extract", jsonExtractFunc, -1, 0 }, - { "json_nextract", jsonExtractFunc, -1, JSON_NULLERR }, - { "->", jsonExtractFunc, 2, JSON_NULLERR|JSON_ABPATH }, - { "->>", jsonExtractFunc, 2, JSON_ABPATH }, - { "json_insert", jsonSetFunc, -1, 0 }, - { "json_object", jsonObjectFunc, -1, 0 }, - { "json_patch", jsonPatchFunc, 2, 0 }, - { "json_quote", jsonQuoteFunc, 1, 0 }, - { "json_remove", jsonRemoveFunc, -1, 0 }, - { "json_replace", jsonReplaceFunc, -1, 0 }, - { "json_set", jsonSetFunc, -1, JSON_ISSET }, - { "json_type", jsonTypeFunc, 1, 0 }, - { "json_ntype", jsonTypeFunc, 1, JSON_NULLERR }, - { "json_type", jsonTypeFunc, 2, 0 }, - { "json_valid", jsonValidFunc, 1, 0 }, - +/* +** Register JSON functions. +*/ +void sqlite3RegisterJsonFunctions(void){ +#ifndef SQLITE_OMIT_JSON + static FuncDef aJsonFunc[] = { - JFUNCTION(json, 1, 0, jsonRemoveFunc), - JFUNCTION(json_array, -1, 0, jsonArrayFunc), - JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), - JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), - JFUNCTION(json_extract, -1, 0, jsonExtractFunc), - JFUNCTION(json_insert, -1, 0, jsonSetFunc), - JFUNCTION(json_object, -1, 0, jsonObjectFunc), - JFUNCTION(json_patch, 2, 0, jsonPatchFunc), - JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), - JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), - JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), - JFUNCTION(json_set, -1, 1, jsonSetFunc), - JFUNCTION(json_type, 1, 0, jsonTypeFunc), - JFUNCTION(json_type, 2, 0, jsonTypeFunc), - JFUNCTION(json_valid, 1, 0, jsonValidFunc), ++ JFUNCTION(json, 1, 0, jsonRemoveFunc), ++ JFUNCTION(json_array, -1, 0, jsonArrayFunc), ++ JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc), ++ JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc), ++ JFUNCTION(json_extract, -1, 0, jsonExtractFunc), ++ JFUNCTION(json_nextract, -1, JSON_NULLERR, jsonExtractFunc), ++ JFUNCTION(->, 2, JSON_NULLERR|JSON_ABPATH, jsonExtractFunc), ++ JFUNCTION(->>, 2, JSON_ABPATH, jsonExtractFunc), ++ JFUNCTION(json_insert, -1, 0, jsonSetFunc), ++ JFUNCTION(json_ntype, 1, JSON_NULLERR, jsonTypeFunc), ++ JFUNCTION(json_object, -1, 0, jsonObjectFunc), ++ JFUNCTION(json_patch, 2, 0, jsonPatchFunc), ++ JFUNCTION(json_quote, 1, 0, jsonQuoteFunc), ++ JFUNCTION(json_remove, -1, 0, jsonRemoveFunc), ++ JFUNCTION(json_replace, -1, 0, jsonReplaceFunc), ++ JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc), ++ JFUNCTION(json_type, 1, 0, jsonTypeFunc), ++ JFUNCTION(json_type, 2, 0, jsonTypeFunc), ++ JFUNCTION(json_valid, 1, 0, jsonValidFunc), #if SQLITE_DEBUG - JFUNCTION(json_parse, 1, 0, jsonParseFunc), - JFUNCTION(json_test1, 1, 0, jsonTest1Func), - /* DEBUG and TESTING functions */ - { "json_parse", jsonParseFunc, 1, 0 }, - { "json_test1", jsonTest1Func, 1, 0 }, ++ JFUNCTION(json_parse, 1, 0, jsonParseFunc), ++ JFUNCTION(json_test1, 1, 0, jsonTest1Func), #endif - WAGGREGATE(json_group_array, 1, 0, 0, ++ WAGGREGATE(json_group_array, 1, 0, 0, + jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse, + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS), - WAGGREGATE(json_group_object, 2, 0, 0, ++ WAGGREGATE(json_group_object, 2, 0, 0, + jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse, + SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS) }; + sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc)); +#endif +} + +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) +/* +** Register the JSON table-valued functions +*/ +int sqlite3JsonTableFunctions(sqlite3 *db){ + int rc = SQLITE_OK; static const struct { - const char *zName; - int nArg; - void (*xStep)(sqlite3_context*,int,sqlite3_value**); - void (*xFinal)(sqlite3_context*); - void (*xValue)(sqlite3_context*); - } aAgg[] = { - { "json_group_array", 1, - jsonArrayStep, jsonArrayFinal, jsonArrayValue }, - { "json_group_object", 2, - jsonObjectStep, jsonObjectFinal, jsonObjectValue }, - }; -#ifndef SQLITE_OMIT_VIRTUALTABLE - static const struct { -- const char *zName; -- sqlite3_module *pModule; ++ const char *zName; ++ sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule },