diff options
author | drh <> | 2023-04-28 17:38:35 +0000 |
---|---|---|
committer | drh <> | 2023-04-28 17:38:35 +0000 |
commit | 8e7efe37645453fac5ca98f8a9837f34d14f75b6 (patch) | |
tree | 7f22fbdf69f6dcf485b46bdf5062f0d53a938b68 | |
parent | 272ae627c535b1ee11b82ba045c641945e34bdc5 (diff) | |
download | sqlite-8e7efe37645453fac5ca98f8a9837f34d14f75b6.tar.gz sqlite-8e7efe37645453fac5ca98f8a9837f34d14f75b6.zip |
Improvements to the accuracy of json_error(). Add the extension SQL
functions random_json(SEED) and random_json5(SEED).
FossilOrigin-Name: 8d09dc1c45a8026b94f70273d064e47939f30cadedc17548b5a26ba054a8d3a7
-rw-r--r-- | ext/misc/randomjson.c | 202 | ||||
-rw-r--r-- | manifest | 13 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/json.c | 8 |
4 files changed, 214 insertions, 11 deletions
diff --git a/ext/misc/randomjson.c b/ext/misc/randomjson.c new file mode 100644 index 000000000..3a6f545fe --- /dev/null +++ b/ext/misc/randomjson.c @@ -0,0 +1,202 @@ +/* +** 2023-04-28 +** +** 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 SQLite extension implements a the random_json(SEED) and +** random_json5(SEED) functions. Given a numeric SEED value, these +** routines generate pseudo-random JSON or JSON5, respectively. The +** same value is always generated for the same seed. +** +** These SQL functions are intended for testing. They do not have any +** practical real-world use, that we know of. +** +** COMPILE: +** +** gcc --shared -fPIC -o randomjson.so -I. ext/misc/randomjson.c +** +** USING FROM THE CLI: +** +** .load ./randomjson +** SELECT random_json(1); +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +/* Pseudo-random number generator */ +typedef struct Prng { + unsigned int x, y; +} Prng; + +/* Reseed the PRNG */ +static void prngSeed(Prng *p, unsigned int iSeed){ + p->x = iSeed | 1; + p->y = iSeed; +} + +/* Extract a random number */ +static unsigned int prngInt(Prng *p){ + p->x = (p->x>>1) ^ ((1+~(p->x&1)) & 0xd0000001); + p->y = p->y*1103515245 + 12345; + return p->x ^ p->y; +} + +static const char *azJsonAtoms[] = { + /* JSON /* JSON-5 */ + "0", "0", + "1", "1", + "-1", "-1", + "2", "+2", + "3", "3", + "2.5", "2.5", + "0.75", ".75", + "-4.0e2", "-4.e2", + "5.0e-3", "+5e-3", + "0", "0x0", + "512", "0x200", + "256", "+0x100", + "-2748", "-0xabc", + "true", "true", + "false", "false", + "null", "null", + "9.0e999", "Infinity", + "-9.0e999", "-Infinity", + "9.0e999", "+Infinity", + "null", "NaN", + "-0.0005123", "-0.0005123", + "4.35e-3", "+4.35e-3", + "\"gem\\\"hay\"", "\"gem\\\"hay\"", + "\"icy'joy\"", "'icy\\'joy\'", + "\"keylog\"", "\"key\\\nlog\"", + "\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"", + "{}", "{}", + "[]", "[]", + "[]", "[/*empty*/]", + "{}", "{//empty\n}", + "\"ask\"", "\"ask\"", + "\"bag\"", "\"bag\"", + "\"can\"", "\"can\"", + "\"day\"", "\"day\"", + "\"end\"", "'end'", + "\"fly\"", "\"fly\"", + "\"\"", "\"\"", +}; +static const char *azJsonTemplate[] = { + /* JSON JSON-5 */ + "{\"a\":%,\"b\":%,\"c\":%}", "{a:%,b:%,c:%}", + "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}", + "{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,\"\":%}", + "{\"d\":%}", "{d:%}", + "{\"eeee\":%, \"ffff\":%}", "{eeee:% /*and*/, ffff:%}", + "{\"$g\":%,\"_h_\":%}", "{$g:%,_h_:%,}", + "{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}", + "{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}", + "{\"a b c d\":%,e:%,f:%,x:%,y:%}", + "{\"Z\":%}", "{Z:%,}", + "[%]", "[%,]", + "[%,%]", "[%,%]", + "[%,%,%]", "[%,%,%,]", + "[%,%,%,%]", "[%,%,%,%]", + "[%,%,%,%,%]", "[%,%,%,%,%]", +}; + +#define count(X) (sizeof(X)/sizeof(X[0])) + +#define STRSZ 10000 + +static void jsonExpand( + const char *zSrc, + char *zDest, + Prng *p, + int eType, /* 0 for JSON, 1 for JSON5 */ + unsigned int r /* Growth probability 0..1000. 0 means no growth */ +){ + unsigned int i, j, k; + const char *z; + size_t n; + + j = 0; + if( zSrc==0 ){ + k = prngInt(p)%(count(azJsonTemplate)/2); + k = k*2 + eType; + zSrc = azJsonTemplate[k]; + } + if( strlen(zSrc)>=STRSZ/10 ) r = 0; + for(i=0; zSrc[i]; i++){ + if( zSrc[i]!='%' ){ + if( j<STRSZ ) zDest[j++] = zSrc[i]; + continue; + } + if( r==0 || (r<1000 && (prngInt(p)%1000)<=r) ){ + /* Fill in without values without any new % */ + k = prngInt(p)%(count(azJsonAtoms)/2); + k = k*2 + eType; + z = azJsonAtoms[k]; + }else{ + /* Add new % terms */ + k = prngInt(p)%(count(azJsonTemplate)/2); + k = k*2 + eType; + z = azJsonTemplate[k]; + } + n = strlen(z); + if( j+n<STRSZ ){ + memcpy(&zDest[j], z, n); + j += n; + } + } + zDest[STRSZ-1] = 0; + if( j<STRSZ ) zDest[j] = 0; +} + +static void randJsonFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + unsigned int iSeed; + int eType = *(int*)sqlite3_user_data(context); + Prng prng; + char z1[STRSZ+1], z2[STRSZ+1]; + + iSeed = (unsigned int)sqlite3_value_int(argv[0]); + prngSeed(&prng, iSeed); + jsonExpand(0, z2, &prng, eType, 1000); + jsonExpand(z2, z1, &prng, eType, 1000); + jsonExpand(z1, z2, &prng, eType, 100); + jsonExpand(z2, z1, &prng, eType, 0); + sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT); +} + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_randomjson_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + static int cOne = 1; + static int cZero = 0; + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "random_json", 1, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, + &cZero, randJsonFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "random_json5", 1, + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, + &cOne, randJsonFunc, 0, 0); + } + return rc; +} @@ -1,5 +1,5 @@ -C Add\sthe\sjson_error(X)\sfunction\sthat\sreturns\sthe\s1-based\scharacter\soffset\sto\nthe\sfirst\ssyntax\serror\sin\sJSON5\sstring\sX,\sor\s0\sif\sthere\sare\sno\serrors. -D 2023-04-28T14:48:11.699 +C Improvements\sto\sthe\saccuracy\sof\sjson_error().\s\sAdd\sthe\sextension\sSQL\nfunctions\srandom_json(SEED)\sand\srandom_json5(SEED). +D 2023-04-28T17:38:35.385 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -301,6 +301,7 @@ F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 F ext/misc/qpvtab.c 09738419e25f603a35c0ac8bd0a04daab794f48d08a9bc07a6085b9057b99009 +F ext/misc/randomjson.c 7dd13664155319d47b9facc0d8dbf45e13062966a47168e54e3f26d48240d7ea F ext/misc/regexp.c f50ab59bfa8934b7ed98de069d2c74c187f2ef523fb09e85f8840f6459a90942 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -593,7 +594,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4 -F src/json.c b532d42d310e570d7f620a692a26f21dc7306063b866088c4e43c647a17118b3 +F src/json.c 03eba427c0e8700db2895b785642f4dba8440020658d8eef97ec4fadf3836cdf F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136 F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d @@ -2066,8 +2067,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 629db09fceb7bf37561b52ccee06ebf4df261291e9a8ffcca82b243f6db5ff07 -R cda10fe16274848e02e4d5ea3713e4b9 +P 901ad995d5a722ca2672516205ff488e9acd703a828ca5fc43f11fca5f2af120 +R c710d125f016d21291562e41606e0d2f U drh -Z 80f17384e6d82e3c8657040553f2124e +Z 98bfef108d9db21095967c25b17439f3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0b6e554ed..2d0bc4dda 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -901ad995d5a722ca2672516205ff488e9acd703a828ca5fc43f11fca5f2af120
\ No newline at end of file +8d09dc1c45a8026b94f70273d064e47939f30cadedc17548b5a26ba054a8d3a7
\ No newline at end of file diff --git a/src/json.c b/src/json.c index d1a057b48..f76d7dc5a 100644 --- a/src/json.c +++ b/src/json.c @@ -1093,7 +1093,7 @@ json_parse_restart: pParse->has5 = 1; x = k; }else{ - pParse->iErr = j; + if( x!=-1 ) pParse->iErr = j; return -1; } } @@ -1114,7 +1114,7 @@ json_parse_restart: } x = jsonParseValue(pParse, j); if( x!=(-5) ){ - pParse->iErr = j; + if( x!=(-1) ) pParse->iErr = j; return -1; } j = pParse->iErr+1; @@ -1123,7 +1123,7 @@ json_parse_restart: x = jsonParseValue(pParse, j); pParse->iDepth--; if( x<=0 ){ - pParse->iErr = j; + if( x!=(-1) ) pParse->iErr = j; return -1; } j = x; @@ -1174,7 +1174,7 @@ json_parse_restart: if( pParse->nNode!=(u32)iThis+1 ) pParse->has5 = 1; break; } - pParse->iErr = j; + if( x!=(-1) ) pParse->iErr = j; return -1; } j = x; |