123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /*
- ** 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);
- ** SELECT random_json5(1);
- */
- #ifdef SQLITE_STATIC_RANDOMJSON
- # include "sqlite3.h"
- #else
- # include "sqlite3ext.h"
- SQLITE_EXTENSION_INIT1
- #endif
- #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 char *azJsonAtoms[] = {
- /* JSON JSON-5 */
- "0", "0",
- "1", "1",
- "-1", "-1",
- "2", "+2",
- "3DDDD", "3DDDD",
- "2.5DD", "2.5DD",
- "0.75", ".75",
- "-4.0e2", "-4.e2",
- "5.0e-3", "+5e-3",
- "6.DDe+0DD", "6.DDe+0DD",
- "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.0005DD", "-0.0005DD",
- "4.35e-3", "+4.35e-3",
- "\"gem\\\"hay\"", "\"gem\\\"hay\"",
- "\"icy'joy\"", "'icy\\'joy\'",
- "\"keylog\"", "\"key\\\nlog\"",
- "\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"",
- "\"oat\\r\\n\"", "\"oat\\r\\n\"",
- "\"\\fpan\\b\"", "\"\\fpan\\b\"",
- "{}", "{}",
- "[]", "[]",
- "[]", "[/*empty*/]",
- "{}", "{//empty\n}",
- "\"ask\"", "\"ask\"",
- "\"bag\"", "\"bag\"",
- "\"can\"", "\"can\"",
- "\"day\"", "\"day\"",
- "\"end\"", "'end'",
- "\"fly\"", "\"fly\"",
- "\"\\u00XX\\u00XX\"", "\"\\xXX\\xXX\"",
- "\"y\\uXXXXz\"", "\"y\\uXXXXz\"",
- "\"\"", "\"\"",
- };
- static char *azJsonTemplate[] = {
- /* JSON JSON-5 */
- "{\"a\":%,\"b\":%,\"cDD\":%}", "{a:%,b:%,cDD:%}",
- "{\"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_\":%,\"a b c d\":%}", "{$g:%,_h_:%,\"a b c d\":%}",
- "{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}",
- "{\"\\u00XX\":%,\"\\uXXXX\":%}", "{\"\\xXX\":%,\"\\uXXXX\":%}",
- "{\"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;
- char *z;
- char *zX;
- size_t n;
- char zBuf[200];
- j = 0;
- if( zSrc==0 ) zSrc = "%";
- 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( (zX = strstr(z,"XX"))!=0 ){
- unsigned int y = prngInt(p);
- if( (y&0xff)==((y>>8)&0xff) ) y += 0x100;
- while( (y&0xff)==((y>>16)&0xff) || ((y>>8)&0xff)==((y>>16)&0xff) ){
- y += 0x10000;
- }
- memcpy(zBuf, z, n+1);
- z = zBuf;
- zX = strstr(z,"XX");
- while( zX!=0 ){
- zX[0] = "0123456789abcdef"[y%16]; y /= 16;
- zX[1] = "0123456789abcdef"[y%16]; y /= 16;
- zX = strstr(zX, "XX");
- }
- }else if( (zX = strstr(z,"DD"))!=0 ){
- unsigned int y = prngInt(p);
- memcpy(zBuf, z, n+1);
- z = zBuf;
- zX = strstr(z,"DD");
- while( zX!=0 ){
- zX[0] = "0123456789"[y%10]; y /= 10;
- zX[1] = "0123456789"[y%10]; y /= 10;
- zX = strstr(zX, "DD");
- }
- }
- assert( strstr(z, "XX")==0 );
- assert( strstr(z, "DD")==0 );
- if( j+n<STRSZ ){
- memcpy(&zDest[j], z, n);
- j += (int)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;
- #ifdef SQLITE_STATIC_RANDOMJSON
- (void)pApi; /* Unused parameter */
- #else
- SQLITE_EXTENSION_INIT2(pApi);
- #endif
- (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;
- }
|