]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge the JSON function enhancements from the json-enhancements branch into
authordrh <>
Sat, 8 Jan 2022 15:37:13 +0000 (15:37 +0000)
committerdrh <>
Sat, 8 Jan 2022 15:37:13 +0000 (15:37 +0000)
json-in-core.

FossilOrigin-Name: e116501c2f0e594eb7a3dd804daa943cc508f32ded3078aed21b695ec83bcd4c

1  2 
Makefile.msc
manifest
manifest.uuid
src/callback.c
src/json.c

diff --cc Makefile.msc
Simple merge
diff --cc manifest
index c39afa35cd481e21da73c1d7f8cadd726603b3ca,38810b62bc976f0eaa53bae109953027d40f9c1b..b3ac61a7f5d5445d62a707d19c3592f00e069f22
+++ 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 8d5afef0f445af40bd5343075d31cf5b56ef01a6,dc1aa1ea0ee9c72d7e9f3bda01112538f1d8785d..3d3e816e87dd782f6d8a3f612210db5695534871
@@@ -1,1 -1,1 +1,1 @@@
- 583b47d865fb8d2c9ae4d3a4e70356a8a758978efb0a282f6b19775bf41fb748
 -4d81425e1bf2cff6fa961d0a7936b5f62d3f8ffe9bffea89c1e8b8ddf8fad6f4
++e116501c2f0e594eb7a3dd804daa943cc508f32ded3078aed21b695ec83bcd4c
diff --cc src/callback.c
index 936c374abd7e04fd47cfcfc67c18a52aa0e3a8c9,936c374abd7e04fd47cfcfc67c18a52aa0e3a8c9..7d8f9dcbced3d26d5c655222e06e59d9090e5293
@@@ -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 5f39902c0ec8ed7c6085fbb59fc4065566ff47b6,26f08e9168d154ab5c0f38e3f576a342a4899921..aad45077672d986fb9c65da988613574c2212e51
@@@ -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; i<argc; i++){
-     zPath = (const char*)sqlite3_value_text(argv[i]);
-     pNode = jsonLookup(p, zPath, 0, ctx);
-     if( p->nErr ) 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; i<argc; i++){
+       zPath = (const char*)sqlite3_value_text(argv[i]);
+       pNode = jsonLookup(p, zPath, 0, ctx);
+       if( p->nErr ) 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               },