mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Improvements to the accuracy of json_error(). Add the extension SQL
functions random_json(SEED) and random_json5(SEED). FossilOrigin-Name: 8d09dc1c45a8026b94f70273d064e47939f30cadedc17548b5a26ba054a8d3a7
This commit is contained in:
202
ext/misc/randomjson.c
Normal file
202
ext/misc/randomjson.c
Normal file
@ -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;
|
||||||
|
}
|
13
manifest
13
manifest
@ -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.
|
C Improvements\sto\sthe\saccuracy\sof\sjson_error().\s\sAdd\sthe\sextension\sSQL\nfunctions\srandom_json(SEED)\sand\srandom_json5(SEED).
|
||||||
D 2023-04-28T14:48:11.699
|
D 2023-04-28T17:38:35.385
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -301,6 +301,7 @@ F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d
|
|||||||
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
|
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
|
||||||
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
|
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
|
||||||
F ext/misc/qpvtab.c 09738419e25f603a35c0ac8bd0a04daab794f48d08a9bc07a6085b9057b99009
|
F ext/misc/qpvtab.c 09738419e25f603a35c0ac8bd0a04daab794f48d08a9bc07a6085b9057b99009
|
||||||
|
F ext/misc/randomjson.c 7dd13664155319d47b9facc0d8dbf45e13062966a47168e54e3f26d48240d7ea
|
||||||
F ext/misc/regexp.c f50ab59bfa8934b7ed98de069d2c74c187f2ef523fb09e85f8840f6459a90942
|
F ext/misc/regexp.c f50ab59bfa8934b7ed98de069d2c74c187f2ef523fb09e85f8840f6459a90942
|
||||||
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
|
||||||
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
|
||||||
@ -593,7 +594,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
|||||||
F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
|
F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
|
||||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||||
F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4
|
F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4
|
||||||
F src/json.c b532d42d310e570d7f620a692a26f21dc7306063b866088c4e43c647a17118b3
|
F src/json.c 03eba427c0e8700db2895b785642f4dba8440020658d8eef97ec4fadf3836cdf
|
||||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||||
F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136
|
F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136
|
||||||
F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
|
F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
|
||||||
@ -2066,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 629db09fceb7bf37561b52ccee06ebf4df261291e9a8ffcca82b243f6db5ff07
|
P 901ad995d5a722ca2672516205ff488e9acd703a828ca5fc43f11fca5f2af120
|
||||||
R cda10fe16274848e02e4d5ea3713e4b9
|
R c710d125f016d21291562e41606e0d2f
|
||||||
U drh
|
U drh
|
||||||
Z 80f17384e6d82e3c8657040553f2124e
|
Z 98bfef108d9db21095967c25b17439f3
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
901ad995d5a722ca2672516205ff488e9acd703a828ca5fc43f11fca5f2af120
|
8d09dc1c45a8026b94f70273d064e47939f30cadedc17548b5a26ba054a8d3a7
|
@ -1093,7 +1093,7 @@ json_parse_restart:
|
|||||||
pParse->has5 = 1;
|
pParse->has5 = 1;
|
||||||
x = k;
|
x = k;
|
||||||
}else{
|
}else{
|
||||||
pParse->iErr = j;
|
if( x!=-1 ) pParse->iErr = j;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1114,7 +1114,7 @@ json_parse_restart:
|
|||||||
}
|
}
|
||||||
x = jsonParseValue(pParse, j);
|
x = jsonParseValue(pParse, j);
|
||||||
if( x!=(-5) ){
|
if( x!=(-5) ){
|
||||||
pParse->iErr = j;
|
if( x!=(-1) ) pParse->iErr = j;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
j = pParse->iErr+1;
|
j = pParse->iErr+1;
|
||||||
@ -1123,7 +1123,7 @@ json_parse_restart:
|
|||||||
x = jsonParseValue(pParse, j);
|
x = jsonParseValue(pParse, j);
|
||||||
pParse->iDepth--;
|
pParse->iDepth--;
|
||||||
if( x<=0 ){
|
if( x<=0 ){
|
||||||
pParse->iErr = j;
|
if( x!=(-1) ) pParse->iErr = j;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
j = x;
|
j = x;
|
||||||
@ -1174,7 +1174,7 @@ json_parse_restart:
|
|||||||
if( pParse->nNode!=(u32)iThis+1 ) pParse->has5 = 1;
|
if( pParse->nNode!=(u32)iThis+1 ) pParse->has5 = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pParse->iErr = j;
|
if( x!=(-1) ) pParse->iErr = j;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
j = x;
|
j = x;
|
||||||
|
Reference in New Issue
Block a user