]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Extend the enhancement to json_set() and json_replace(). Clean up cruft. json-opt-rcstr
authordrh <>
Wed, 26 Jul 2023 01:05:08 +0000 (01:05 +0000)
committerdrh <>
Wed, 26 Jul 2023 01:05:08 +0000 (01:05 +0000)
FossilOrigin-Name: 2dbb22c75e86f2e3ced38ac14b4943570d5c2f86cd5e37e875bf0c863be28836

manifest
manifest.uuid
src/json.c
src/printf.c
src/sqliteInt.h
src/vdbemem.c

index 875c31732870682811abf7d1da3b69465c23c574..b712bbf97f39db227cd113f9a3c4ca6200bfa5bc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sJsonParse.zAlt\sfield\sto\sold\srevised\sJSON\stext\safter\sa\schange.\nDemonstrate\sthat\sthis\selminates\sthe\sneed\sfor\sreparsing\safter\sa\schange\nby\susing\sit\sin\sthe\sjson_remove()\sfunction.\s\sThis\sis\san\sincremental\scheck-in\ncontaining\slots\sof\scruft.
-D 2023-07-26T00:48:45.768
+C Extend\sthe\senhancement\sto\sjson_set()\sand\sjson_replace().\s\sClean\sup\scruft.
+D 2023-07-26T01:05:08.003
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -598,7 +598,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
-F src/json.c a7823b0593eac42a608f8439e6b1f28022ac5fce9aa81a82856e48dd07ab601d
+F src/json.c 790ca70b1f8884610fe5401ac6f260d955d47d9c14c9f3d2aa6541fd881faf07
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
 F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002
@@ -634,7 +634,7 @@ F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
 F src/pragma.c 37b8fb02d090262280c86e1e2654bf59d8dbfbfe8dc6733f2b968a11374c095a
 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
 F src/prepare.c d6c4354f8ea0dc06962fbabc4b68c4471a45276a2918c929be00f9f537f69eb1
-F src/printf.c 56e362bbefbe61b5b211f1886e3cdb9b25d8ba817c12df3a15f11b9bdc152efd
+F src/printf.c e3ba080e2f409f9bfcc8d34724e6fc160e9c718dc92d0548f6b71b8b6f860ce2
 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
@@ -643,7 +643,7 @@ F src/shell.c.in d320d8a13636de06d777cc1eab981caca304e175464e98183cf4ea68d93db81
 F src/sqlite.h.in f999ef3642f381d69679b2516b430dbcb6c5a2a951b7f5e43dc4751b474a5774
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
-F src/sqliteInt.h 29c8e6d0b6dfa9c2c356f23ab8349d7fac3679d5f7cfc01d4ee45c9171db2960
+F src/sqliteInt.h 30d7b0d586a4d03a384dcb60088c81b6fc6f74ce85cc3a0b3242eedc3cc24dbd
 F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -714,7 +714,7 @@ F src/vdbeInt.h 401813862f9d75af01bdb2ab99253ad019e9d6ddcc8058e4fa61a43e9a60d1f7
 F src/vdbeapi.c dde6c4d0f87486f056b9db4d1ea185bb1d84a6839102b86e76316ba590d07cc7
 F src/vdbeaux.c b5e3f7e158518b4eca6f166ac43900640a3fe9735c710e12bfa119af21059339
 F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
-F src/vdbemem.c 46ea371b10c3573cf9287d385411fbcc6cd42099ad3505d20e33f2f3ed91537d
+F src/vdbemem.c 33da4f30ddba2670bc1e617c3262b66aef2a8039043d4ff93e5c97974991089d
 F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
 F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
@@ -2044,8 +2044,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P afe02a398a16d51bd7482b6fbe2fbd15d9ac4fd9cdbc9d2bf81f38b3391fc567
-R 33c717c250039ffbe53dc8d7b2094929
+P f930b139d6db0ee799bc90397b225175103c4bf22923d1c9cbcd32509adc1738
+R 80113afdab5484e027b5180529a678b7
 U drh
-Z 96ad60bdf5cbde0ec2b901493a583f6e
+Z dc859019c8db0487fd3e03bdb875d59d
 # Remove this line to create a well-formed Fossil manifest.
index dce111985027b6a8864d728212885941ef7ad11e..4bbeaca0dbefb11b1e6b9ef4fb1cd2d9340f74d2 100644 (file)
@@ -1 +1 @@
-f930b139d6db0ee799bc90397b225175103c4bf22923d1c9cbcd32509adc1738
\ No newline at end of file
+2dbb22c75e86f2e3ced38ac14b4943570d5c2f86cd5e37e875bf0c863be28836
\ No newline at end of file
index d7d464442b14a1101b66acaf4c63d678316fcd0d..a4a3e65c92834325ea0c6ae4c0a7f82897a00bd1 100644 (file)
@@ -1758,7 +1758,6 @@ static int jsonParse(
   int i;
   memset(pParse, 0, sizeof(*pParse));
   if( zJson==0 ) return 1;
-//printf("PARSE %s\n", zJson);
   pParse->zJson = zJson;
   pParse->bOwnsJson = bTakeJson;
   pParse->nJPRef = 1;
@@ -1896,7 +1895,6 @@ static JsonParse *jsonParseCached(
       p->nErr = 0;
       p->useMod = 0;
       pMatch = p;
-//printf("HIT %s at %d\n", zJson, iKey);
     }else
     if( pMatch==0
      && p->zAlt!=0
@@ -1907,7 +1905,6 @@ static JsonParse *jsonParseCached(
       p->nErr = 0;
       p->useMod = 1;
       pMatch = p;
-//printf("HIT %s at %d-alt\n", zJson, iKey);
     }else if( p->iHold<iMinHold ){
       iMinHold = p->iHold;
       iMinKey = iKey;
@@ -1928,7 +1925,6 @@ static JsonParse *jsonParseCached(
   /* The input JSON was not found anywhere in the cache.  We will need
   ** to parse it ourselves and generate a new JsonParse object.
   */
-//printf("MISS %s\n", zJson);
   p = sqlite3_malloc64( sizeof(*p) );
   if( p==0 ){
     sqlite3_result_error_nomem(pCtx);
@@ -2866,7 +2862,7 @@ static void jsonReplaceFunc(
   int argc,
   sqlite3_value **argv
 ){
-  JsonParse x;          /* The parse */
+  JsonParse *pParse;          /* The parse */
   JsonNode *pNode;
   const char *zPath;
   u32 i;
@@ -2876,20 +2872,20 @@ static void jsonReplaceFunc(
     jsonWrongNumArgs(ctx, "replace");
     return;
   }
-  if( jsonParse(&x, ctx, (char*)sqlite3_value_text(argv[0]), 0) ) return;
-  assert( x.nNode );
+  pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
+  if( pParse==0 ) return;
   for(i=1; i<(u32)argc; i+=2){
     zPath = (const char*)sqlite3_value_text(argv[i]);
-    pNode = jsonLookup(&x, zPath, 0, ctx);
-    if( x.nErr ) goto replace_err;
+    pParse->useMod = 1;
+    pNode = jsonLookup(pParse, zPath, 0, ctx);
+    if( pParse->nErr ) goto replace_err;
     if( pNode ){
-      jsonReplaceNode(ctx, &x, (u32)(pNode - x.aNode), argv[i+1]);
+      jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
     }
   }
-  jsonReturnJson(&x, x.aNode, ctx, 0);
+  jsonReturnJson(pParse, pParse->aNode, ctx, 1);
 replace_err:
-  jsonDebugPrintParse(&x);
-  jsonParseReset(&x);
+  jsonDebugPrintParse(pParse);
 }
 
 
@@ -2910,7 +2906,7 @@ static void jsonSetFunc(
   int argc,
   sqlite3_value **argv
 ){
-  JsonParse x;          /* The parse */
+  JsonParse *pParse;       /* The parse */
   JsonNode *pNode;
   const char *zPath;
   u32 i;
@@ -2922,27 +2918,27 @@ static void jsonSetFunc(
     jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
     return;
   }
-  if( jsonParse(&x, ctx, (char*)sqlite3_value_text(argv[0]), 0) ) return;
-  assert( x.nNode );
+  pParse = jsonParseCached(ctx, argv[0], ctx, argc>1);
+  if( pParse==0 ) return;
   for(i=1; i<(u32)argc; i+=2){
     zPath = (const char*)sqlite3_value_text(argv[i]);
     bApnd = 0;
-    x.useMod = 1;
-    pNode = jsonLookup(&x, zPath, &bApnd, ctx);
-    if( x.oom ){
+    pParse->useMod = 1;
+    pNode = jsonLookup(pParse, zPath, &bApnd, ctx);
+    if( pParse->oom ){
       sqlite3_result_error_nomem(ctx);
       goto jsonSetDone;
-    }else if( x.nErr ){
+    }else if( pParse->nErr ){
       goto jsonSetDone;
     }else if( pNode && (bApnd || bIsSet) ){
-      jsonReplaceNode(ctx, &x, (u32)(pNode - x.aNode), argv[i+1]);
+      jsonReplaceNode(ctx, pParse, (u32)(pNode - pParse->aNode), argv[i+1]);
     }
   }
-  jsonDebugPrintParse(&x);
-  jsonReturnJson(&x, x.aNode, ctx, 0);
+  jsonDebugPrintParse(pParse);
+  jsonReturnJson(pParse, pParse->aNode, ctx, 1);
 
 jsonSetDone:
-  jsonParseReset(&x);
+  /* no cleanup required */;
 }
 
 /*
index a55bd2b85b1b55eb33cb89765426cc48bc7ff7db..87ad91f7953007420492b2accdb89afa77bf2d41 100644 (file)
@@ -1394,34 +1394,13 @@ void sqlite3RCStrUnref(char *z){
   assert( p!=0 );
   p--;
   assert( p->nRCRef>0 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
   if( p->nRCRef>=2 ){
     p->nRCRef--;
   }else{
-    if( p->xFree ) p->xFree(p->pAttach);
-#ifdef SQLITE_DEBUG
-    p->uMagic = 0;
-#endif
     sqlite3_free(p);
   }
 }
 
-#if 0
-/*
-** Return true if the reference count on the string is exactly one, meaning
-** that the string can be modified.  Return false if the reference count
-** is greater than one.
-*/
-int sqlite3RCStrIsWriteable(char *z){
-  RCStr *p = (RCStr*)z;
-  assert( p!=0 );
-  p--;
-  assert( p->nRCRef>0 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
-  return p->nRCRef==1;
-}
-#endif
-
 /*
 ** Create a new string that is capable of holding N bytes of text, not counting
 ** the zero byte at the end.  The string is uninitialized.
@@ -1435,32 +1414,9 @@ char *sqlite3RCStrNew(u64 N){
   RCStr *p = sqlite3_malloc64( N + sizeof(*p) + 1 );
   if( p==0 ) return 0;
   p->nRCRef = 1;
-  p->xFree = 0;
-  p->pAttach = 0;
-#ifdef SQLITE_DEBUG
-  p->uMagic = SQLITE_RCSTR_MAGIC;
-#endif
   return (char*)&p[1];
 }
 
-#if 0
-/*
-** Return the number of bytes allocated to the string.  The value returned
-** does not include the space for the zero-terminator at the end.
-*/
-u64 sqlite3RCStrSize(char *z){
-  RCStr *p = (RCStr*)z;
-  u64 N;
-  assert( p!=0 );
-  p--;
-  assert( p->nRCRef>0 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
-  N = sqlite3_msize(p);
-  N -= sizeof(p) + 1;
-  return N;
-}
-#endif
-
 /*
 ** Change the size of the string so that it is able to hold N bytes.
 ** The string might be reallocated, so return the new allocation.
@@ -1471,7 +1427,6 @@ char *sqlite3RCStrResize(char *z, u64 N){
   assert( p!=0 );
   p--;
   assert( p->nRCRef==1 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
   pNew = sqlite3_realloc64(p, N+sizeof(RCStr)+1);
   if( pNew==0 ){
     sqlite3_free(p);
@@ -1480,40 +1435,3 @@ char *sqlite3RCStrResize(char *z, u64 N){
     return (char*)&pNew[1];
   }
 }
-
-#if 0
-/*
-** Add a new attachment to the string.
-**
-** A string may have no more than one attachment.  When a new attachment
-** is added, any prior attachment is destroyed.  Remove an attachment
-** by adding a zero-attachment.
-*/
-void sqlite3RCStrAttach(char *z, void *pAttach, void(*xFree)(void*)){
-  RCStr *p = (RCStr*)z;
-  assert( p!=0 );
-  p--;
-  assert( p->nRCRef>0 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
-  if( p->xFree ) p->xFree(p->pAttach);
-  p->xFree = xFree;
-  p->pAttach = pAttach;
-}
-#endif
-
-#if 0
-/*
-** Return the attachment associated with a string if the attachment
-** has the destructure specified in the second argument.  If the
-** string has no attachment or if the destructor does not match,
-** then return a NULL pointr.
-*/
-void *sqlite3RCStrGetAttachment(char *z, void(*xFree)(void*)){
-  RCStr *p = (RCStr*)z;
-  assert( p!=0 );
-  p--;
-  assert( p->nRCRef>0 );
-  assert( p->uMagic==SQLITE_RCSTR_MAGIC );
-  return p->xFree==xFree ? p->pAttach : 0;
-}
-#endif
index 358063534f7a171d8274bf63c7f8413a44d9021c..a19a16d50dab94dd9e430b8d47ebb76cea007bab 100644 (file)
@@ -4066,44 +4066,22 @@ struct sqlite3_str {
 ** The following object is the header for an "RCStr" or "reference-counted
 ** string".  An RCStr is passed around and used like any other char*
 ** that has been dynamically allocated.  The important interface
-** difference is that it uses sqlite3RCStrUnref() as its destructor
-** rather than sqlite3_free().  Other than that the two are interchangeable.
+** differences:
 **
-** Thus to return an RCStr object as the result of an SQL function use:
-** 
-**    sqlite3_result_text64(ctx,z,sz,sqlite3RCStrUnref,SQLITE_UTF8)
-**                                   ^^^^^^^^^^^^^^^^^
-**                                   Instead of sqlite3_free() or similar
+**   1.  RCStr strings are reference counted.  They are deallocated
+**       when the reference count reaches zero.
 **
-** An SQL function can check its arguments to see if they are RCStr
-** strings using the sqlite3ValueIsOfClass() function:
+**   2.  Use sqlite3RCStrUnref() to free an RCStr string rather than
+**       sqlite3_free()
 **
-**    sqlite3ValueIsOfClass(argv[i], sqlite3RCStrUnref);
-**
-** An RCStr string might be better than an ordinary string in some cases
-** because:
-**
-**    (1)  You can duplicate it using sqlite3RCStrRef(x).
-**
-**    (2)  You can also add an associated object to the string.  For
-**         example, if the string is JSON, perhaps the associated object
-**         is a parse of that JSON.
-**
-** Methods for an RCStr string begin with "sqlite3RCStr...".
+**   3.  Make a (read-only) copy of a read-only RCStr string using
+**       sqlite3RCStrRef().
 */
 struct RCStr {
-  u32 nRCRef;            /* Number of references */
-#ifdef SQLITE_DEBUG
-  u32 uMagic;            /* Magic number for sanity checking */
-#endif
-  void *pAttach;         /* Attachment to this string */
-  void (*xFree)(void*);  /* Destructor for the attachment */
+  u64 nRCRef;            /* Number of references */
+  /* Total structure size should be a multiple of 8 bytes for alignment */
 };
 
-/* The Magic number used by RCStr for sanity checking.  SQLITE_DEBUG only. */
-#define SQLITE_RCSTR_MAGIC 0x3dc05d54
-
-
 /*
 ** A pointer to this structure is used to communicate information
 ** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
@@ -5222,7 +5200,6 @@ void sqlite3FileSuffix3(const char*, char*);
 u8 sqlite3GetBoolean(const char *z,u8);
 
 const void *sqlite3ValueText(sqlite3_value*, u8);
-//int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*));
 int sqlite3ValueBytes(sqlite3_value*, u8);
 void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
                         void(*)(void*));
@@ -5333,11 +5310,7 @@ int sqlite3OpenTempDatabase(Parse *);
 char *sqlite3RCStrRef(char*);
 void sqlite3RCStrUnref(char*);
 char *sqlite3RCStrNew(u64);
-//u64 sqlite3RCStrSize(char*);
 char *sqlite3RCStrResize(char*,u64);
-//int sqlite3RCStrIsWriteable(char*);
-//void sqlite3RCStrAttach(char*, void*, void(*)(void*));
-//void *sqlite3RCStrGetAttachment(char*,void(*)(void*));
 
 void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
 int sqlite3StrAccumEnlarge(StrAccum*, i64);
index d44a41716f09e29ea433d1d1562de50fdea35184..c73e59c362a6b16636110d122bd97a962f1c0538 100644 (file)
@@ -1368,26 +1368,6 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
   return valueToText(pVal, enc);
 }
 
-#if 0
-/* Return true if sqlit3_value object pVal is a string or blob value
-** that uses the destructor specified in the second argument.
-**
-** TODO:  Maybe someday promote this interface into a published API so
-** that third-party extensions can get access to it?
-*/
-int sqlite3ValueIsOfClass(const sqlite3_value *pVal, void(*xFree)(void*)){
-  if( ALWAYS(pVal!=0)
-   && (pVal->flags & (MEM_Str|MEM_Blob))!=0
-   && (pVal->flags & MEM_Dyn)!=0
-   && pVal->xDel==xFree
-  ){
-    return 1;
-  }else{
-    return 0;
-  }
-}
-#endif
-
 /*
 ** Create a new sqlite3_value object.
 */