From: drh Date: Thu, 13 Aug 2015 13:54:59 +0000 (+0000) Subject: Experimental code (untested) for a JSONB datatype. X-Git-Tag: version-3.9.0~204^2~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd0621b360ec250683d77a8a5cd3b8ed49ddd017;p=thirdparty%2Fsqlite.git Experimental code (untested) for a JSONB datatype. FossilOrigin-Name: e3596ac7b1dd5bde3f9cae5781a6806d8d9f7166 --- diff --git a/ext/misc/json.c b/ext/misc/json.c index 8acbb9bf5f..4f3e1c02bb 100644 --- a/ext/misc/json.c +++ b/ext/misc/json.c @@ -23,6 +23,55 @@ ** input is understood to be JSONB if it a BLOB and JSON if the input is ** of any other type. Functions that begin with the "json_" prefix return ** JSON and functions that begin with "jsonb_" return JSONB. +** +** JSONB format: +** +** A JSONB blob is a sequence of terms. Each term begins with a single +** variable length integer X which determines the type and size of the term. +** +** type = X%8 +** size = X>>3 +** +** Term types are 0 through 7 for null, true, false, integer, real, string, +** array, and object. The meaning of size depends on the type. +** +** For null, true, and false terms, the size is always 0. +** +** For integer terms, the size is the number of bytes that contains the +** integer value. The value is stored as big-endian twos-complement. +** +** For real terms, the size is always 8 and the value is a big-ending +** double-precision floating-point number. +** +** For string terms, the size is the number of bytes in the string. The +** string itself immediately follows the X integer. There are no escapes +** and the string is not zero-terminated. The string is always stored as +** UTF8. +** +** For array terms, the size is the number of bytes in content. The +** content consists of zero or more additional terms that are the elements +** of the array. +** +** For object terms, the size is the number of bytes of content. The +** content is zero or more pairs of terms. The first element of each +** pair is a string term which is the label and the second element is +** the value. +** +** Variable Length Integers: +** +** The variable length integer encoding is the 64-bit unsigned integer encoding +** originally developed for SQLite4. The encoding for each integer is between +** 1 and 9 bytes. Call those bytes A0 through A8. The encoding is as follows: +** +** If A0 is between 0 and 240 inclusive, then the value is A0. +** +** If A0 is between 241 and 248 inclusive, then the value is +** 240+256*(A0-241)+A1. +** +** If A0 is 249 then the value is 2288+256*A1+A2. +** +** If A0 is 250 or more then the value is a (A0-247)-byte big-endian +** integer taken from starting at A1. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 @@ -34,12 +83,13 @@ typedef sqlite3_uint64 u64; typedef unsigned int u32; typedef unsigned char u8; -/* An instance of this object represents a JSON string under construction. +/* An instance of this object represents a JSON string or +** JSONB blob under construction. */ typedef struct Json Json; struct Json { sqlite3_context *pCtx; /* Function context - put error messages here */ - char *zBuf; /* Append JSON text here */ + char *zBuf; /* Append JSON or JSONB content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ @@ -47,6 +97,73 @@ struct Json { char zSpace[100]; /* Initial static space */ }; +/* JSONB type values +*/ +#define JSONB_NULL 0 +#define JSONB_TRUE 1 +#define JSONB_FALSE 2 +#define JSONB_INT 3 +#define JSONB_REAL 4 +#define JSONB_STRING 5 +#define JSONB_ARRAY 6 +#define JSONB_OBJECT 7 + +#if 0 +/* +** Decode the varint in the first n bytes z[]. Write the integer value +** into *pResult and return the number of bytes in the varint. +** +** If the decode fails because there are not enough bytes in z[] then +** return 0; +*/ +static int jsonGetVarint64( + const unsigned char *z, + int n, + u64 *pResult +){ + unsigned int x; + if( n<1 ) return 0; + if( z[0]<=240 ){ + *pResult = z[0]; + return 1; + } + if( z[0]<=248 ){ + if( n<2 ) return 0; + *pResult = (z[0]-241)*256 + z[1] + 240; + return 2; + } + if( nzBuf[p->nUsed++] = '"'; } -/* Make pJson the result of the SQL function. +/* +** Write a 32-bit unsigned integer as 4 big-endian bytes. +*/ +static void jsonPutInt32(unsigned char *z, unsigned int y){ + z[0] = (unsigned char)(y>>24); + z[1] = (unsigned char)(y>>16); + z[2] = (unsigned char)(y>>8); + z[3] = (unsigned char)(y); +} + + +/* Write integer X as a variable-length integer into the buffer z[]. +** z[] is guaranteed to be at least 9 bytes in length. Return the +** number of bytes written. +*/ +int jsonPutVarint64(char *zIn, u64 x){ + unsigned char *z = (unsigned char*)zIn; + unsigned int w, y; + if( x<=240 ){ + z[0] = (unsigned char)x; + return 1; + } + if( x<=2287 ){ + y = (unsigned int)(x - 240); + z[0] = (unsigned char)(y/256 + 241); + z[1] = (unsigned char)(y%256); + return 2; + } + if( x<=67823 ){ + y = (unsigned int)(x - 2288); + z[0] = 249; + z[1] = (unsigned char)(y/256); + z[2] = (unsigned char)(y%256); + return 3; + } + y = (unsigned int)x; + w = (unsigned int)(x>>32); + if( w==0 ){ + if( y<=16777215 ){ + z[0] = 250; + z[1] = (unsigned char)(y>>16); + z[2] = (unsigned char)(y>>8); + z[3] = (unsigned char)(y); + return 4; + } + z[0] = 251; + jsonPutInt32(z+1, y); + return 5; + } + if( w<=255 ){ + z[0] = 252; + z[1] = (unsigned char)w; + jsonPutInt32(z+2, y); + return 6; + } + if( w<=65535 ){ + z[0] = 253; + z[1] = (unsigned char)(w>>8); + z[2] = (unsigned char)w; + jsonPutInt32(z+3, y); + return 7; + } + if( w<=16777215 ){ + z[0] = 254; + z[1] = (unsigned char)(w>>16); + z[2] = (unsigned char)(w>>8); + z[3] = (unsigned char)w; + jsonPutInt32(z+4, y); + return 8; + } + z[0] = 255; + jsonPutInt32(z+1, w); + jsonPutInt32(z+5, y); + return 9; +} + + +/* Append integer X as a variable-length integer on the JSONB currently +** under construction in p. +*/ +static void jsonAppendVarint(Json *p, u64 X){ + if( (p->nUsed+9 > p->nAlloc) && jsonGrow(p,9)!=0 ) return; + p->nUsed += jsonPutVarint64(p->zBuf+p->nUsed, X); +} + +/* Make the JSON in p the result of the SQL function. */ static void jsonResult(Json *p){ if( p->mallocFailed==0 ){ @@ -150,6 +352,17 @@ static void jsonResult(Json *p){ assert( p->bStatic ); } +/* Make the JSONB in p the result of the SQL function. +*/ +static void jsonbResult(Json *p){ + if( p->mallocFailed==0 ){ + sqlite3_result_blob(p->pCtx, p->zBuf, p->nUsed, + p->bStatic ? SQLITE_TRANSIENT : sqlite3_free); + jsonZero(p); + } + assert( p->bStatic ); +} + /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument @@ -197,6 +410,55 @@ static void jsonArrayFunc( jsonResult(&jx); } +/* +** Implementation of the jsonb_array(VALUE,...) function. Return a JSON +** array that contains all values given in arguments. Or if any argument +** is a BLOB, throw an error. +*/ +static void jsonbArrayFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int i; + Json jx; + + jsonInit(&jx, context); + jx.nUsed = 5; + for(i=0; i