mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Code and comment cleanup. Everything should work the same.
FossilOrigin-Name: c640754df0d3ffdad994745f0d0e10c8f19f424b87f6a6e6e269491a0350b950
This commit is contained in:
12
manifest
12
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sharmless\scompiler\swarnings.\s\sRefactor\ssome\sidentifier\snames\sfor\nclearer\spresentation.
|
||||
D 2023-12-02T18:17:38.516
|
||||
C Code\sand\scomment\scleanup.\s\sEverything\sshould\swork\sthe\ssame.
|
||||
D 2023-12-02T20:25:36.578
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -688,7 +688,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 b67328611c8ebc5aca49e2d73b1bad9962948aa5c952f3d96c44eb74ee3d0010
|
||||
F src/json.c 5ad1a1be6199359b09bb4eca690789b77375e00f17c55697b6288f1b0fbbe8b0
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
|
||||
@@ -2145,8 +2145,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 1304534001e9ef66c6b12752b69d790bfa3427cc803f87cc48ca22ae12df0fdf
|
||||
R 1b492fad564bbccdff370d30a804d641
|
||||
P 7e3941502789c5afaf19b08112f464abf5e3cba7f92fc9290af2a0f96127ad9a
|
||||
R 9f984966a856d28c36c8f0d6d69732a4
|
||||
U drh
|
||||
Z f1274565e5b6e1f5da018a4ab14dfe40
|
||||
Z ea3e13091dceb571341f1dccf0e97828
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
7e3941502789c5afaf19b08112f464abf5e3cba7f92fc9290af2a0f96127ad9a
|
||||
c640754df0d3ffdad994745f0d0e10c8f19f424b87f6a6e6e269491a0350b950
|
||||
201
src/json.c
201
src/json.c
@@ -133,12 +133,13 @@
|
||||
#define JSONB_ARRAY 11 /* An array */
|
||||
#define JSONB_OBJECT 12 /* An object */
|
||||
|
||||
/* Human-readable names for the JSONB values:
|
||||
/* Human-readable names for the JSONB values. The index for each
|
||||
** string must correspond to the JSONB_* integer above.
|
||||
*/
|
||||
static const char * const jsonbType[] = {
|
||||
"null", "true", "false", "integer", "integer",
|
||||
"real", "real", "text", "text", "text",
|
||||
"text", "array", "object"
|
||||
"text", "array", "object", "", "", "", ""
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -168,7 +169,7 @@ static const char jsonIsSpace[] = {
|
||||
#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
|
||||
|
||||
/*
|
||||
** Characters that are special to JSON. Control charaters,
|
||||
** Characters that are special to JSON. Control characters,
|
||||
** '"' and '\\'.
|
||||
*/
|
||||
static const char jsonIsOk[256] = {
|
||||
@@ -204,7 +205,6 @@ typedef struct JsonCache JsonCache;
|
||||
typedef struct JsonString JsonString;
|
||||
typedef struct JsonParse JsonParse;
|
||||
|
||||
|
||||
/*
|
||||
** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
|
||||
*/
|
||||
@@ -213,8 +213,14 @@ typedef struct JsonParse JsonParse;
|
||||
|
||||
/* A cache mapping JSON text into JSONB blobs.
|
||||
**
|
||||
** All content, both JSON text and the JSONB blobs, is stored as RCStr
|
||||
** objects.
|
||||
** Each cache entry is a JsonParse object with the following restrictions:
|
||||
**
|
||||
** * The bReadOnly flag must be set
|
||||
**
|
||||
** * The aBlob[] array must be owned by the JsonParse object. In other
|
||||
** words, nBlobAlloc must be non-zero.
|
||||
**
|
||||
** * zJson must be an RCStr. In other words bJsonIsRCStr must be true.
|
||||
*/
|
||||
struct JsonCache {
|
||||
sqlite3 *db; /* Database connection */
|
||||
@@ -225,6 +231,10 @@ struct JsonCache {
|
||||
/* An instance of this object represents a JSON string
|
||||
** under construction. Really, this is a generic string accumulator
|
||||
** that can be and is used to create strings other than JSON.
|
||||
**
|
||||
** If the generated string is longer than will fit into the zSpace[] buffer,
|
||||
** then it will be an RCStr string. This aids with caching of large
|
||||
** JSON strings.
|
||||
*/
|
||||
struct JsonString {
|
||||
sqlite3_context *pCtx; /* Function context - put error messages here */
|
||||
@@ -260,18 +270,17 @@ struct JsonString {
|
||||
/* A parsed JSON value. Lifecycle:
|
||||
**
|
||||
** 1. JSON comes in and is parsed into a JSONB value in aBlob. The
|
||||
** original text is stored in zJson.
|
||||
** original text is stored in zJson. This step is skipped if the
|
||||
** input is JSONB instead of text JSON.
|
||||
**
|
||||
** 2. The aBlob is searched using the JSON path notation, if needed.
|
||||
** 2. The aBlob[] array is searched using the JSON path notation, if needed.
|
||||
**
|
||||
** 3. Zero or more changes are made to aBlob (via json_remove() or
|
||||
** json_replace() or similar).
|
||||
** 3. Zero or more changes are made to aBlob[] (via json_remove() or
|
||||
** json_replace() or json_patch() or similar).
|
||||
**
|
||||
** 4. New JSON text is generated from the aBlob for output.
|
||||
**
|
||||
** Step 1 is omitted if the input is a BLOB in the JSONB format. Step 4
|
||||
** is omitted if the output is JSONB or some other value that is not
|
||||
** JSON text.
|
||||
** 4. New JSON text is generated from the aBlob[] for output. This step
|
||||
** is skipped the function is one of the jsonb_* functions that returns
|
||||
** JSONB instead of text JSON.
|
||||
*/
|
||||
struct JsonParse {
|
||||
u8 *aBlob; /* JSONB representation of JSON value */
|
||||
@@ -326,7 +335,6 @@ static void jsonReturnParse(sqlite3_context*,JsonParse*);
|
||||
static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
|
||||
static void jsonParseFree(JsonParse*);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
** Utility routines for dealing with JsonCache objects
|
||||
**************************************************************************/
|
||||
@@ -346,11 +354,11 @@ static void jsonCacheDeleteGeneric(void *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert a new entry into the cache. If the cache is full, expell
|
||||
** Insert a new entry into the cache. If the cache is full, expel
|
||||
** the least recently used entry. Return SQLITE_OK on success or a
|
||||
** result code otherwise.
|
||||
**
|
||||
** Both the input JSON and JSONB must be RCStr objects.
|
||||
** Cache entries are stored in age order, oldest first.
|
||||
*/
|
||||
static int jsonCacheInsert(
|
||||
sqlite3_context *ctx, /* The SQL statement context holding the cache */
|
||||
@@ -386,7 +394,14 @@ static int jsonCacheInsert(
|
||||
|
||||
/*
|
||||
** Search for a cached translation the json text supplied by pArg. Return
|
||||
** the JsonParse object if found.
|
||||
** the JsonParse object if found. Return NULL if not found.
|
||||
**
|
||||
** When a match if found, the matching entry is moved to become the
|
||||
** most-recently used entry if it isn't so already.
|
||||
**
|
||||
** The JsonParse object returned still belongs to the Cache and might
|
||||
** be deleted at any moment. If the caller whants the JsonParse to
|
||||
** linger, it needs to increment the nPJRef reference counter.
|
||||
*/
|
||||
static JsonParse *jsonCacheSearch(
|
||||
sqlite3_context *ctx, /* The SQL statement context holding the cache */
|
||||
@@ -419,6 +434,7 @@ static JsonParse *jsonCacheSearch(
|
||||
}
|
||||
if( i<p->nUsed ){
|
||||
if( i<p->nUsed-1 ){
|
||||
/* Make the matching entry the most recently used entry */
|
||||
JsonParse *tmp = p->a[i];
|
||||
memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
|
||||
p->a[p->nUsed-1] = tmp;
|
||||
@@ -561,7 +577,9 @@ static void jsonStringTerminate(JsonString *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to force the string to be a zero-terminated RCStr string.
|
||||
/* Try to force the string to be a zero-terminated RCStr string. In other
|
||||
** words, make sure it is not still using the internal zSpace[] static
|
||||
** buffer.
|
||||
**
|
||||
** Return true on success. Return false if an OOM prevents this
|
||||
** from happening.
|
||||
@@ -591,9 +609,12 @@ static void jsonAppendSeparator(JsonString *p){
|
||||
}
|
||||
|
||||
/* Append the N-byte string in zIn to the end of the JsonString string
|
||||
** under construction. Enclose the string in "..." and escape
|
||||
** any double-quotes or backslash characters contained within the
|
||||
** under construction. Enclose the string in double-quotes ("...") and
|
||||
** escape any double-quotes or backslash characters contained within the
|
||||
** string.
|
||||
**
|
||||
** This routine is a high-runner. There is a measurable performance
|
||||
** increase associated with unwinding the jsonIsOk[] loop.
|
||||
*/
|
||||
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
|
||||
u32 k;
|
||||
@@ -604,8 +625,8 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
|
||||
p->zBuf[p->nUsed++] = '"';
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
k = 0;
|
||||
while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; }
|
||||
while( k<N && jsonIsOk[z[k]] ){ k++; }
|
||||
while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; } /* <--, */
|
||||
while( k<N && jsonIsOk[z[k]] ){ k++; } /* <-- loop unwound for speed */
|
||||
if( k>=N ){
|
||||
if( k>0 ){
|
||||
memcpy(&p->zBuf[p->nUsed], z, k);
|
||||
@@ -783,12 +804,8 @@ static void jsonParseReset(JsonParse *pParse){
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a JsonParse object that was obtained from sqlite3_malloc().
|
||||
**
|
||||
** Note that destroying JsonParse might call sqlite3RCStrUnref() to
|
||||
** destroy the zJson value. The RCStr object might recursively invoke
|
||||
** JsonParse to destroy this pParse object again. Take care to ensure
|
||||
** that this recursive destructor sequence terminates harmlessly.
|
||||
** Decrement the reference count on the JsonParse object. When the
|
||||
** count reaches zero, free the object.
|
||||
*/
|
||||
static void jsonParseFree(JsonParse *pParse){
|
||||
if( pParse ){
|
||||
@@ -1010,7 +1027,6 @@ static void jsonWrongNumArgs(
|
||||
** Utility routines for dealing with the binary BLOB representation of JSON
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
** Expand pParse->aBlob so that it holds at least N bytes.
|
||||
**
|
||||
@@ -2068,7 +2084,8 @@ static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
|
||||
}
|
||||
|
||||
/*
|
||||
** Edit the size of the element at iRoot by the amount in pParse->delta.
|
||||
** Edit the payload size of the element at iRoot by the amount in
|
||||
** pParse->delta.
|
||||
*/
|
||||
static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
|
||||
u32 sz = 0;
|
||||
@@ -2126,6 +2143,55 @@ static void jsonBlobEdit(
|
||||
#define JSON_LOOKUP_PATHERROR 0xfffffffd
|
||||
#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
|
||||
|
||||
/* Forward declaration */
|
||||
static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
|
||||
|
||||
|
||||
/* This helper routine for jsonLookupStep() populates pIns with
|
||||
** binary data that is to be inserted into pParse.
|
||||
**
|
||||
** In the common case, pIns just points to pParse->aIns and pParse->nIns.
|
||||
** But if the zPath of the original edit operation includes path elements
|
||||
** that go deeper, additional substructure must be created.
|
||||
**
|
||||
** For example:
|
||||
**
|
||||
** json_insert('{}', '$.a.b.c', 123);
|
||||
**
|
||||
** The search stops at '$.a' But additional substructure must be
|
||||
** created for the ".b.c" part of the patch so that the final result
|
||||
** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with
|
||||
** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
|
||||
**
|
||||
** The caller is responsible for resetting pIns when it has finished
|
||||
** using the substructure.
|
||||
*/
|
||||
static u32 jsonCreateEditSubstructure(
|
||||
JsonParse *pParse, /* The original JSONB that is being edited */
|
||||
JsonParse *pIns, /* Populate this with the blob data to insert */
|
||||
const char *zTail /* Tail of the path that determins substructure */
|
||||
){
|
||||
static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
|
||||
int rc;
|
||||
memset(pIns, 0, sizeof(*pIns));
|
||||
if( zTail[0]==0 ){
|
||||
/* No substructure. Just insert what is given in pParse. */
|
||||
pIns->aBlob = pParse->aIns;
|
||||
pIns->nBlob = pParse->nIns;
|
||||
rc = 0;
|
||||
}else{
|
||||
/* Construct the binary substructure */
|
||||
pIns->nBlob = 1;
|
||||
pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
|
||||
pIns->eEdit = pParse->eEdit;
|
||||
pIns->nIns = pParse->nIns;
|
||||
pIns->aIns = pParse->aIns;
|
||||
rc = jsonLookupStep(pIns, 0, zTail, 0);
|
||||
pParse->oom |= pIns->oom;
|
||||
}
|
||||
return rc; /* Error code only */
|
||||
}
|
||||
|
||||
/*
|
||||
** Search along zPath to find the Json element specified. Return an
|
||||
** index into pParse->aBlob[] for the start of that element's value.
|
||||
@@ -2135,6 +2201,13 @@ static void jsonBlobEdit(
|
||||
** label, before returning.
|
||||
**
|
||||
** Return one of the JSON_LOOKUP error codes if problems are seen.
|
||||
**
|
||||
** This routine will also modify the blob. If pParse->eEdit is one of
|
||||
** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
|
||||
** made to the selected value. If an edit is performed, then the return
|
||||
** value does not necessarily point to the select element. If an edit
|
||||
** is performed, the return value is only useful for detecting error
|
||||
** conditions.
|
||||
*/
|
||||
static u32 jsonLookupStep(
|
||||
JsonParse *pParse, /* The JSON to search */
|
||||
@@ -2145,7 +2218,6 @@ static u32 jsonLookupStep(
|
||||
u32 i, j, k, nKey, sz, n, iEnd, rc;
|
||||
const char *zKey;
|
||||
u8 x;
|
||||
static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
|
||||
|
||||
if( zPath[0]==0 ){
|
||||
if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
|
||||
@@ -2224,26 +2296,12 @@ static u32 jsonLookupStep(
|
||||
testcase( pParse->eEdit==JEDIT_SET );
|
||||
memset(&ix, 0, sizeof(ix));
|
||||
jsonBlobAppendNode(&ix,JSONB_TEXTRAW, nKey, 0);
|
||||
memset(&v, 0, sizeof(v));
|
||||
if( zPath[i]==0 ){
|
||||
v.nBlob = pParse->nIns;
|
||||
v.aBlob = pParse->aIns;
|
||||
}else{
|
||||
v.nBlob = 1;
|
||||
v.aBlob = (u8*)&emptyObject[zPath[i]=='.'];
|
||||
v.eEdit = pParse->eEdit;
|
||||
v.nIns = pParse->nIns;
|
||||
v.aIns = pParse->aIns;
|
||||
rc = jsonLookupStep(&v, 0, &zPath[i], 0);
|
||||
if( JSON_LOOKUP_ISERROR(rc) || v.oom ){
|
||||
pParse->oom |= v.oom;
|
||||
jsonParseReset(&v);
|
||||
jsonParseReset(&ix);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
pParse->oom |= ix.oom;
|
||||
if( jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob) ){
|
||||
rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
|
||||
if( !JSON_LOOKUP_ISERROR(rc)
|
||||
&& jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
|
||||
){
|
||||
assert( !pParse->oom );
|
||||
nIns = ix.nBlob + nKey + v.nBlob;
|
||||
jsonBlobEdit(pParse, j, 0, 0, nIns);
|
||||
if( !pParse->oom ){
|
||||
@@ -2257,7 +2315,7 @@ static u32 jsonLookupStep(
|
||||
}
|
||||
jsonParseReset(&v);
|
||||
jsonParseReset(&ix);
|
||||
return j;
|
||||
return rc;
|
||||
}
|
||||
}else if( zPath[0]=='[' ){
|
||||
x = pParse->aBlob[iRoot] & 0x0f;
|
||||
@@ -2309,29 +2367,16 @@ static u32 jsonLookupStep(
|
||||
JsonParse v;
|
||||
testcase( pParse->eEdit==JEDIT_INS );
|
||||
testcase( pParse->eEdit==JEDIT_SET );
|
||||
memset(&v, 0, sizeof(v));
|
||||
if( zPath[i+1]==0 ){
|
||||
v.aBlob = pParse->aIns;
|
||||
v.nBlob = pParse->nIns;
|
||||
}else{
|
||||
v.nBlob = 1;
|
||||
v.aBlob = (u8*)&emptyObject[zPath[i+1]=='.'];
|
||||
v.eEdit = pParse->eEdit;
|
||||
v.nIns = pParse->nIns;
|
||||
v.aIns = pParse->aIns;
|
||||
rc = jsonLookupStep(&v, 0, &zPath[i+1], 0);
|
||||
if( JSON_LOOKUP_ISERROR(rc) || v.oom ){
|
||||
pParse->oom |= v.oom;
|
||||
jsonParseReset(&v);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( jsonBlobMakeEditable(pParse, v.nBlob) ){
|
||||
rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
|
||||
if( !JSON_LOOKUP_ISERROR(rc)
|
||||
&& jsonBlobMakeEditable(pParse, v.nBlob)
|
||||
){
|
||||
assert( !pParse->oom );
|
||||
jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
|
||||
}
|
||||
jsonParseReset(&v);
|
||||
if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
|
||||
return j;
|
||||
return rc;
|
||||
}
|
||||
}else{
|
||||
return JSON_LOOKUP_PATHERROR;
|
||||
@@ -3169,17 +3214,7 @@ static void jsonArrayLengthFunc(
|
||||
i = 0;
|
||||
}
|
||||
if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
|
||||
u32 n, sz = 0, iEnd;
|
||||
n = jsonbPayloadSize(p, i, &sz);
|
||||
if( n==0 ) eErr = 2;
|
||||
iEnd = i+n+sz;
|
||||
i += n;
|
||||
while( eErr==0 && i<iEnd ){
|
||||
cnt++;
|
||||
n = jsonbPayloadSize(p, i, &sz);
|
||||
if( n==0 ) eErr = 2;
|
||||
i += n+sz;
|
||||
}
|
||||
cnt = jsonbArrayCount(p, i);
|
||||
}
|
||||
if( eErr ){
|
||||
if( eErr==2 ) sqlite3_result_error(ctx, "malformed JSON", -1);
|
||||
|
||||
Reference in New Issue
Block a user