#ifndef SQLITE_OMIT_JSON
#include "sqliteInt.h"
static const char jsonIsSpace[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
# define VVA(X)
#else
# define VVA(X) X
#endif
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;
struct JsonString {
sqlite3_context *pCtx;
char *zBuf;
u64 nAlloc;
u64 nUsed;
u8 bStatic;
u8 bErr;
char zSpace[100];
};
#define JSON_NULL 0
#define JSON_TRUE 1
#define JSON_FALSE 2
#define JSON_INT 3
#define JSON_REAL 4
#define JSON_STRING 5
#define JSON_ARRAY 6
#define JSON_OBJECT 7
#define JSON_SUBTYPE 74
static const char * const jsonType[] = {
"null", "true", "false", "integer", "real", "text", "array", "object"
};
#define JNODE_RAW 0x01
#define JNODE_ESCAPE 0x02
#define JNODE_REMOVE 0x04
#define JNODE_REPLACE 0x08
#define JNODE_PATCH 0x10
#define JNODE_APPEND 0x20
#define JNODE_LABEL 0x40
#define JNODE_JSON5 0x80
struct JsonNode {
u8 eType;
u8 jnFlags;
u8 eU;
u32 n;
union {
const char *zJContent;
u32 iAppend;
u32 iKey;
u32 iReplace;
JsonNode *pPatch;
} u;
};
struct JsonParse {
u32 nNode;
u32 nAlloc;
JsonNode *aNode;
const char *zJson;
u32 *aUp;
u16 iDepth;
u8 nErr;
u8 oom;
u8 hasNonstd;
int nJson;
u32 iErr;
u32 iHold;
};
#define JSON_MAX_DEPTH 1000
static void jsonZero(JsonString *p){
p->zBuf = p->zSpace;
p->nAlloc = sizeof(p->zSpace);
p->nUsed = 0;
p->bStatic = 1;
}
static void jsonInit(JsonString *p, sqlite3_context *pCtx){
p->pCtx = pCtx;
p->bErr = 0;
jsonZero(p);
}
static void jsonReset(JsonString *p){
if( !p->bStatic ) sqlite3_free(p->zBuf);
jsonZero(p);
}
static void jsonOom(JsonString *p){
p->bErr = 1;
sqlite3_result_error_nomem(p->pCtx);
jsonReset(p);
}
static int jsonGrow(JsonString *p, u32 N){
u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
if( p->bErr ) return 1;
zNew = sqlite3_malloc64(nTotal);
if( zNew==0 ){
jsonOom(p);
return SQLITE_NOMEM;
}
memcpy(zNew, p->zBuf, (size_t)p->nUsed);
p->zBuf = zNew;
p->bStatic = 0;
}else{
zNew = sqlite3_realloc64(p->zBuf, nTotal);
if( zNew==0 ){
jsonOom(p);
return SQLITE_NOMEM;
}
p->zBuf = zNew;
}
p->nAlloc = nTotal;
return SQLITE_OK;
}
static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
if( N==0 ) return;
if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
va_list ap;
if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
va_start(ap, zFormat);
sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
va_end(ap);
p->nUsed += (int)strlen(p->zBuf+p->nUsed);
}
static void jsonAppendChar(JsonString *p, char c){
if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
p->zBuf[p->nUsed++] = c;
}
static void jsonAppendSeparator(JsonString *p){
char c;
if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1];
if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
}
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
u32 i;
if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
p->zBuf[p->nUsed++] = '"';
for(i=0; i<N; i++){
unsigned char c = ((unsigned const char*)zIn)[i];
if( c=='"' || c=='\\' ){
json_simple_escape:
if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
}else if( c<=0x1f ){
static const char aSpecial[] = {
0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
assert( sizeof(aSpecial)==32 );
assert( aSpecial['\b']=='b' );
assert( aSpecial['\f']=='f' );
assert( aSpecial['\n']=='n' );
assert( aSpecial['\r']=='r' );
assert( aSpecial['\t']=='t' );
if( aSpecial[c] ){
c = aSpecial[c];
goto json_simple_escape;
}
if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
p->zBuf[p->nUsed++] = 'u';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0' + (c>>4);
c = "0123456789abcdef"[c&0xf];
}
p->zBuf[p->nUsed++] = c;
}
p->zBuf[p->nUsed++] = '"';
assert( p->nUsed<p->nAlloc );
}
static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
u32 i;
jsonAppendChar(p, '"');
zIn++;
N -= 2;
while( N>0 ){
for(i=0; i<N && zIn[i]!='\\'; i++){}
if( i>0 ){
jsonAppendRaw(p, zIn, i);
zIn += i;
N -= i;
if( N==0 ) break;
}
assert( zIn[0]=='\\' );
switch( (u8)zIn[1] ){
case '\'':
jsonAppendChar(p, '\'');
break;
case 'v':
jsonAppendRaw(p, "\\u0009", 6);
break;
case 'x':
jsonAppendRaw(p, "\\u00", 4);
jsonAppendRaw(p, &zIn[2], 2);
zIn += 2;
N -= 2;
break;
case '0':
jsonAppendRaw(p, "\\u0000", 6);
break;
case '\r':
if( zIn[2]=='\n' ){
zIn++;
N--;
}
break;
case '\n':
break;
case 0xe2:
assert( N>=4 );
assert( 0x80==(u8)zIn[2] );
assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] );
zIn += 2;
N -= 2;
break;
default:
jsonAppendRaw(p, zIn, 2);
break;
}
zIn += 2;
N -= 2;
}
jsonAppendChar(p, '"');
}
static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
if( zIn[0]=='+' ){
zIn++;
N--;
}else if( zIn[0]=='-' ){
jsonAppendChar(p, '-');
zIn++;
N--;
}
if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){
sqlite3_int64 i = 0;
int rc = sqlite3DecOrHexToI64(zIn, &i);
if( rc<=1 ){
jsonPrintf(100,p,"%lld",i);
}else{
assert( rc==2 );
jsonAppendRaw(p, "9.0e999", 7);
}
return;
}
jsonAppendRaw(p, zIn, N);
}
static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
u32 i;
if( zIn[0]=='+' ){
zIn++;
N--;
}else if( zIn[0]=='-' ){
jsonAppendChar(p, '-');
zIn++;
N--;
}
if( zIn[0]=='.' ){
jsonAppendChar(p, '0');
}
for(i=0; i<N; i++){
if( zIn[i]=='.' && (i+1==N || !sqlite3Isdigit(zIn[i+1])) ){
i++;
jsonAppendRaw(p, zIn, i);
zIn += i;
N -= i;
jsonAppendChar(p, '0');
break;
}
}
if( N>0 ){
jsonAppendRaw(p, zIn, N);
}
}
static void jsonAppendValue(
JsonString *p,
sqlite3_value *pValue
){
switch( sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
jsonAppendRaw(p, "null", 4);
break;
}
case SQLITE_FLOAT: {
jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue));
break;
}
case SQLITE_INTEGER: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
break;
}
case SQLITE_TEXT: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
jsonAppendRaw(p, z, n);
}else{
jsonAppendString(p, z, n);
}
break;
}
default: {
if( p->bErr==0 ){
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
p->bErr = 2;
jsonReset(p);
}
break;
}
}
}
static void jsonResult(JsonString *p){
if( p->bErr==0 ){
sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
SQLITE_UTF8);
jsonZero(p);
}
assert( p->bStatic );
}
static u32 jsonNodeSize(JsonNode *pNode){
return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
}
static void jsonParseReset(JsonParse *pParse){
sqlite3_free(pParse->aNode);
pParse->aNode = 0;
pParse->nNode = 0;
pParse->nAlloc = 0;
sqlite3_free(pParse->aUp);
pParse->aUp = 0;
}
static void jsonParseFree(JsonParse *pParse){
jsonParseReset(pParse);
sqlite3_free(pParse);
}
static void jsonRenderNode(
JsonNode *pNode,
JsonString *pOut,
sqlite3_value **aReplace
){
assert( pNode!=0 );
if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
assert( pNode->eU==4 );
jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
return;
}
assert( pNode->eU==5 );
pNode = pNode->u.pPatch;
}
switch( pNode->eType ){
default: {
assert( pNode->eType==JSON_NULL );
jsonAppendRaw(pOut, "null", 4);
break;
}
case JSON_TRUE: {
jsonAppendRaw(pOut, "true", 4);
break;
}
case JSON_FALSE: {
jsonAppendRaw(pOut, "false", 5);
break;
}
case JSON_STRING: {
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
if( pNode->jnFlags & JNODE_LABEL ){
jsonAppendChar(pOut, '"');
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
jsonAppendChar(pOut, '"');
}else{
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
}
}else if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
}else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
}
break;
}
case JSON_REAL: {
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
}else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
}
break;
}
case JSON_INT: {
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_JSON5 ){
jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
}else{
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
}
break;
}
case JSON_ARRAY: {
u32 j = 1;
jsonAppendChar(pOut, '[');
for(;;){
while( j<=pNode->n ){
if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
jsonAppendSeparator(pOut);
jsonRenderNode(&pNode[j], pOut, aReplace);
}
j += jsonNodeSize(&pNode[j]);
}
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
assert( pNode->eU==2 );
pNode = &pNode[pNode->u.iAppend];
j = 1;
}
jsonAppendChar(pOut, ']');
break;
}
case JSON_OBJECT: {
u32 j = 1;
jsonAppendChar(pOut, '{');
for(;;){
while( j<=pNode->n ){
if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
jsonAppendSeparator(pOut);
jsonRenderNode(&pNode[j], pOut, aReplace);
jsonAppendChar(pOut, ':');
jsonRenderNode(&pNode[j+1], pOut, aReplace);
}
j += 1 + jsonNodeSize(&pNode[j+1]);
}
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
assert( pNode->eU==2 );
pNode = &pNode[pNode->u.iAppend];
j = 1;
}
jsonAppendChar(pOut, '}');
break;
}
}
}
static void jsonReturnJson(
JsonNode *pNode,
sqlite3_context *pCtx,
sqlite3_value **aReplace
){
JsonString s;
jsonInit(&s, pCtx);
jsonRenderNode(pNode, &s, aReplace);
jsonResult(&s);
sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
}
static u8 jsonHexToInt(int h){
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
#ifdef SQLITE_EBCDIC
h += 9*(1&~(h>>4));
#else
h += 9*(1&(h>>6));
#endif
return (u8)(h & 0xf);
}
static u32 jsonHexToInt4(const char *z){
u32 v;
assert( sqlite3Isxdigit(z[0]) );
assert( sqlite3Isxdigit(z[1]) );
assert( sqlite3Isxdigit(z[2]) );
assert( sqlite3Isxdigit(z[3]) );
v = (jsonHexToInt(z[0])<<12)
+ (jsonHexToInt(z[1])<<8)
+ (jsonHexToInt(z[2])<<4)
+ jsonHexToInt(z[3]);
return v;
}
static void jsonReturn(
JsonNode *pNode,
sqlite3_context *pCtx,
sqlite3_value **aReplace
){
switch( pNode->eType ){
default: {
assert( pNode->eType==JSON_NULL );
sqlite3_result_null(pCtx);
break;
}
case JSON_TRUE: {
sqlite3_result_int(pCtx, 1);
break;
}
case JSON_FALSE: {
sqlite3_result_int(pCtx, 0);
break;
}
case JSON_INT: {
sqlite3_int64 i = 0;
int rc;
int bNeg = 0;
const char *z;
assert( pNode->eU==1 );
z = pNode->u.zJContent;
if( z[0]=='-' ){ z++; bNeg = 1; }
else if( z[0]=='+' ){ z++; }
rc = sqlite3DecOrHexToI64(z, &i);
if( rc<=1 ){
sqlite3_result_int64(pCtx, bNeg ? -i : i);
}else if( rc==3 && bNeg ){
sqlite3_result_int64(pCtx, SMALLEST_INT64);
}else{
goto to_double;
}
break;
}
case JSON_REAL: {
double r;
const char *z;
assert( pNode->eU==1 );
to_double:
z = pNode->u.zJContent;
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
sqlite3_result_double(pCtx, r);
break;
}
case JSON_STRING: {
if( pNode->jnFlags & JNODE_RAW ){
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
SQLITE_TRANSIENT);
}else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
SQLITE_TRANSIENT);
}else{
u32 i;
u32 n = pNode->n;
const char *z;
char *zOut;
u32 j;
u32 nOut = n;
assert( pNode->eU==1 );
z = pNode->u.zJContent;
zOut = sqlite3_malloc( nOut+1 );
if( zOut==0 ){
sqlite3_result_error_nomem(pCtx);
break;
}
for(i=1, j=0; i<n-1; i++){
char c = z[i];
if( c=='\\' ){
c = z[++i];
if( c=='u' ){
u32 v = jsonHexToInt4(z+i+1);
i += 4;
if( v==0 ) break;
if( v<=0x7f ){
zOut[j++] = (char)v;
}else if( v<=0x7ff ){
zOut[j++] = (char)(0xc0 | (v>>6));
zOut[j++] = 0x80 | (v&0x3f);
}else{
u32 vlo;
if( (v&0xfc00)==0xd800
&& i<n-6
&& z[i+1]=='\\'
&& z[i+2]=='u'
&& ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
){
v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
i += 6;
zOut[j++] = 0xf0 | (v>>18);
zOut[j++] = 0x80 | ((v>>12)&0x3f);
zOut[j++] = 0x80 | ((v>>6)&0x3f);
zOut[j++] = 0x80 | (v&0x3f);
}else{
zOut[j++] = 0xe0 | (v>>12);
zOut[j++] = 0x80 | ((v>>6)&0x3f);
zOut[j++] = 0x80 | (v&0x3f);
}
}
continue;
}else if( c=='b' ){
c = '\b';
}else if( c=='f' ){
c = '\f';
}else if( c=='n' ){
c = '\n';
}else if( c=='r' ){
c = '\r';
}else if( c=='t' ){
c = '\t';
}else if( c=='v' ){
c = '\v';
}else if( c=='\'' || c=='"' || c=='/' || c=='\\' ){
}else if( c=='0' ){
c = 0;
}else if( c=='x' ){
c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]);
i += 2;
}else if( c=='\r' && z[i+1]=='\n' ){
i++;
continue;
}else if( 0xe2==(u8)c ){
assert( 0x80==(u8)z[i+1] );
assert( 0xa8==(u8)z[i+2] || 0xa9==(u8)z[i+2] );
i += 2;
continue;
}else{
continue;
}
}
zOut[j++] = c;
}
zOut[j] = 0;
sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
}
break;
}
case JSON_ARRAY:
case JSON_OBJECT: {
jsonReturnJson(pNode, pCtx, aReplace);
break;
}
}
}
static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
#if defined(__GNUC__)
# define JSON_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define JSON_NOINLINE __declspec(noinline)
#else
# define JSON_NOINLINE
#endif
static JSON_NOINLINE int jsonParseAddNodeExpand(
JsonParse *pParse,
u32 eType,
u32 n,
const char *zContent
){
u32 nNew;
JsonNode *pNew;
assert( pParse->nNode>=pParse->nAlloc );
if( pParse->oom ) return -1;
nNew = pParse->nAlloc*2 + 10;
pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
if( pNew==0 ){
pParse->oom = 1;
return -1;
}
pParse->nAlloc = nNew;
pParse->aNode = pNew;
assert( pParse->nNode<pParse->nAlloc );
return jsonParseAddNode(pParse, eType, n, zContent);
}
static int jsonParseAddNode(
JsonParse *pParse,
u32 eType,
u32 n,
const char *zContent
){
JsonNode *p;
if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
}
p = &pParse->aNode[pParse->nNode];
p->eType = (u8)(eType & 0xff);
p->jnFlags = (u8)(eType >> 8);
VVA( p->eU = zContent ? 1 : 0 );
p->n = n;
p->u.zJContent = zContent;
return pParse->nNode++;
}
static int jsonIs2Hex(const char *z){
return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
}
static int jsonIs4Hex(const char *z){
return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
}
static int json5Whitespace(const char *zIn){
int n = 0;
const u8 *z = (u8*)zIn;
while( 1 ){
switch( z[n] ){
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x20: {
n++;
break;
}
case '/': {
if( z[n+1]=='*' && z[n+2]!=0 ){
int j;
for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
if( z[j]==0 ) goto whitespace_done;
}
n = j+1;
break;
}else if( z[n+1]=='/' ){
int j;
char c;
for(j=n+2; (c = z[j])!=0; j++){
if( c=='\n' || c=='\r' ) break;
if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
&& (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
){
j += 2;
break;
}
}
n = j;
if( z[n] ) n++;
break;
}
goto whitespace_done;
}
case 0xc2: {
if( z[n+1]==0xa0 ){
n += 2;
break;
}
goto whitespace_done;
}
case 0xe1: {
if( z[n+1]==0x9a && z[n+2]==0x80 ){
n += 3;
break;
}
goto whitespace_done;
}
case 0xe2: {
if( z[n+1]==0x80 ){
u8 c = z[n+2];
if( c<0x80 ) goto whitespace_done;
if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
n += 3;
break;
}
}else if( z[n+1]==0x81 && z[n+2]==0x9f ){
n += 3;
break;
}
goto whitespace_done;
}
case 0xe3: {
if( z[n+1]==0x80 && z[n+2]==0x80 ){
n += 3;
break;
}
goto whitespace_done;
}
case 0xef: {
if( z[n+1]==0xbb && z[n+2]==0xbf ){
n += 3;
break;
}
goto whitespace_done;
}
default: {
goto whitespace_done;
}
}
}
whitespace_done:
return n;
}
static const struct NanInfName {
char c1;
char c2;
char n;
char eType;
char nRepl;
char *zMatch;
char *zRepl;
} aNanInfName[] = {
{ 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" },
{ 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" },
{ 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" },
{ 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" },
{ 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" },
};
static int jsonParseValue(JsonParse *pParse, u32 i){
char c;
u32 j;
int iThis;
int x;
JsonNode *pNode;
const char *z = pParse->zJson;
json_parse_restart:
switch( (u8)z[i] ){
case '{': {
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
pParse->iErr = i;
return -1;
}
for(j=i+1;;j++){
u32 nNode = pParse->nNode;
x = jsonParseValue(pParse, j);
if( x<=0 ){
if( x==(-2) ){
j = pParse->iErr;
if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
break;
}
j += json5Whitespace(&z[j]);
if( sqlite3JsonId1(z[j])
|| (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
){
int k = j+1;
while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
|| (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
){
k++;
}
jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]);
pParse->hasNonstd = 1;
x = k;
}else{
if( x!=-1 ) pParse->iErr = j;
return -1;
}
}
if( pParse->oom ) return -1;
pNode = &pParse->aNode[nNode];
if( pNode->eType!=JSON_STRING ){
pParse->iErr = j;
return -1;
}
pNode->jnFlags |= JNODE_LABEL;
j = x;
if( z[j]==':' ){
j++;
}else{
if( fast_isspace(z[j]) ){
do{ j++; }while( fast_isspace(z[j]) );
if( z[j]==':' ){
j++;
goto parse_object_value;
}
}
x = jsonParseValue(pParse, j);
if( x!=(-5) ){
if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = pParse->iErr+1;
}
parse_object_value:
x = jsonParseValue(pParse, j);
if( x<=0 ){
if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
if( z[j]==',' ){
continue;
}else if( z[j]=='}' ){
break;
}else{
if( fast_isspace(z[j]) ){
do{ j++; }while( fast_isspace(z[j]) );
if( z[j]==',' ){
continue;
}else if( z[j]=='}' ){
break;
}
}
x = jsonParseValue(pParse, j);
if( x==(-4) ){
j = pParse->iErr;
continue;
}
if( x==(-2) ){
j = pParse->iErr;
break;
}
}
pParse->iErr = j;
return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
pParse->iDepth--;
return j+1;
}
case '[': {
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
if( iThis<0 ) return -1;
if( ++pParse->iDepth > JSON_MAX_DEPTH ){
pParse->iErr = i;
return -1;
}
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){
x = jsonParseValue(pParse, j);
if( x<=0 ){
if( x==(-3) ){
j = pParse->iErr;
if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
break;
}
if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
if( z[j]==',' ){
continue;
}else if( z[j]==']' ){
break;
}else{
if( fast_isspace(z[j]) ){
do{ j++; }while( fast_isspace(z[j]) );
if( z[j]==',' ){
continue;
}else if( z[j]==']' ){
break;
}
}
x = jsonParseValue(pParse, j);
if( x==(-4) ){
j = pParse->iErr;
continue;
}
if( x==(-3) ){
j = pParse->iErr;
break;
}
}
pParse->iErr = j;
return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
pParse->iDepth--;
return j+1;
}
case '\'': {
u8 jnFlags;
char cDelim;
pParse->hasNonstd = 1;
jnFlags = JNODE_JSON5;
goto parse_string;
case '"':
jnFlags = 0;
parse_string:
cDelim = z[i];
j = i+1;
for(;;){
c = z[j];
if( (c & ~0x1f)==0 ){
pParse->iErr = j;
return -1;
}
if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
|| (c=='u' && jsonIs4Hex(&z[j+1])) ){
jnFlags |= JNODE_ESCAPE;
}else if( c=='\'' || c=='0' || c=='v' || c=='\n'
|| (0xe2==(u8)c && 0x80==(u8)z[j+1]
&& (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
|| (c=='x' && jsonIs2Hex(&z[j+1])) ){
jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
pParse->hasNonstd = 1;
}else if( c=='\r' ){
if( z[j+1]=='\n' ) j++;
jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
pParse->hasNonstd = 1;
}else{
pParse->iErr = j;
return -1;
}
}else if( c==cDelim ){
break;
}
j++;
}
jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
return j+1;
}
case 't': {
if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
return i+4;
}
pParse->iErr = i;
return -1;
}
case 'f': {
if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
return i+5;
}
pParse->iErr = i;
return -1;
}
case '+': {
u8 seenDP, seenE, jnFlags;
pParse->hasNonstd = 1;
jnFlags = JNODE_JSON5;
goto parse_number;
case '.':
if( sqlite3Isdigit(z[i+1]) ){
pParse->hasNonstd = 1;
jnFlags = JNODE_JSON5;
seenE = 0;
seenDP = JSON_REAL;
goto parse_number_2;
}
pParse->iErr = i;
return -1;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
jnFlags = 0;
parse_number:
seenDP = JSON_INT;
seenE = 0;
assert( '-' < '0' );
assert( '+' < '0' );
assert( '.' < '0' );
c = z[i];
if( c<='0' ){
if( c=='0' ){
if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
assert( seenDP==JSON_INT );
pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5;
for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
goto parse_number_finish;
}else if( sqlite3Isdigit(z[i+1]) ){
pParse->iErr = i+1;
return -1;
}
}else{
if( !sqlite3Isdigit(z[i+1]) ){
if( (z[i+1]=='I' || z[i+1]=='i')
&& sqlite3StrNICmp(&z[i+1], "inf",3)==0
){
pParse->hasNonstd = 1;
if( z[i]=='-' ){
jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
}else{
jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999");
}
return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
}
if( z[i+1]=='.' ){
pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5;
goto parse_number_2;
}
pParse->iErr = i;
return -1;
}
if( z[i+1]=='0' ){
if( sqlite3Isdigit(z[i+2]) ){
pParse->iErr = i+1;
return -1;
}else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5;
for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
goto parse_number_finish;
}
}
}
}
parse_number_2:
for(j=i+1;; j++){
c = z[j];
if( sqlite3Isdigit(c) ) continue;
if( c=='.' ){
if( seenDP==JSON_REAL ){
pParse->iErr = j;
return -1;
}
seenDP = JSON_REAL;
continue;
}
if( c=='e' || c=='E' ){
if( z[j-1]<'0' ){
if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5;
}else{
pParse->iErr = j;
return -1;
}
}
if( seenE ){
pParse->iErr = j;
return -1;
}
seenDP = JSON_REAL;
seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
if( c<'0' || c>'9' ){
pParse->iErr = j;
return -1;
}
continue;
}
break;
}
if( z[j-1]<'0' ){
if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
pParse->hasNonstd = 1;
jnFlags |= JNODE_JSON5;
}else{
pParse->iErr = j;
return -1;
}
}
parse_number_finish:
jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]);
return j;
}
case '}': {
pParse->iErr = i;
return -2;
}
case ']': {
pParse->iErr = i;
return -3;
}
case ',': {
pParse->iErr = i;
return -4;
}
case ':': {
pParse->iErr = i;
return -5;
}
case 0: {
return 0;
}
case 0x09:
case 0x0a:
case 0x0d:
case 0x20: {
do{
i++;
}while( fast_isspace(z[i]) );
goto json_parse_restart;
}
case 0x0b:
case 0x0c:
case '/':
case 0xc2:
case 0xe1:
case 0xe2:
case 0xe3:
case 0xef: {
j = json5Whitespace(&z[i]);
if( j>0 ){
i += j;
pParse->hasNonstd = 1;
goto json_parse_restart;
}
pParse->iErr = i;
return -1;
}
case 'n': {
if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
return i+4;
}
}
default: {
u32 k;
int nn;
c = z[i];
for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
nn = aNanInfName[k].n;
if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
continue;
}
if( sqlite3Isalnum(z[i+nn]) ) continue;
jsonParseAddNode(pParse, aNanInfName[k].eType,
aNanInfName[k].nRepl, aNanInfName[k].zRepl);
pParse->hasNonstd = 1;
return i + nn;
}
pParse->iErr = i;
return -1;
}
}
}
static int jsonParse(
JsonParse *pParse,
sqlite3_context *pCtx,
const char *zJson
){
int i;
memset(pParse, 0, sizeof(*pParse));
if( zJson==0 ) return 1;
pParse->zJson = zJson;
i = jsonParseValue(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
assert( pParse->iDepth==0 );
while( fast_isspace(zJson[i]) ) i++;
if( zJson[i] ){
i += json5Whitespace(&zJson[i]);
if( zJson[i] ){
jsonParseReset(pParse);
return 1;
}
pParse->hasNonstd = 1;
}
}
if( i<=0 ){
if( pCtx!=0 ){
if( pParse->oom ){
sqlite3_result_error_nomem(pCtx);
}else{
sqlite3_result_error(pCtx, "malformed JSON", -1);
}
}
jsonParseReset(pParse);
return 1;
}
return 0;
}
static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
JsonNode *pNode = &pParse->aNode[i];
u32 j;
pParse->aUp[i] = iParent;
switch( pNode->eType ){
case JSON_ARRAY: {
for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
jsonParseFillInParentage(pParse, i+j, i);
}
break;
}
case JSON_OBJECT: {
for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
pParse->aUp[i+j] = i;
jsonParseFillInParentage(pParse, i+j+1, i);
}
break;
}
default: {
break;
}
}
}
static int jsonParseFindParents(JsonParse *pParse){
u32 *aUp;
assert( pParse->aUp==0 );
aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
if( aUp==0 ){
pParse->oom = 1;
return SQLITE_NOMEM;
}
jsonParseFillInParentage(pParse, 0, 0);
return SQLITE_OK;
}
#define JSON_CACHE_ID (-429938)
#define JSON_CACHE_SZ 4
static JsonParse *jsonParseCached(
sqlite3_context *pCtx,
sqlite3_value **argv,
sqlite3_context *pErrCtx
){
const char *zJson = (const char*)sqlite3_value_text(argv[0]);
int nJson = sqlite3_value_bytes(argv[0]);
JsonParse *p;
JsonParse *pMatch = 0;
int iKey;
int iMinKey = 0;
u32 iMinHold = 0xffffffff;
u32 iMaxHold = 0;
if( zJson==0 ) return 0;
for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
if( p==0 ){
iMinKey = iKey;
break;
}
if( pMatch==0
&& p->nJson==nJson
&& memcmp(p->zJson,zJson,nJson)==0
){
p->nErr = 0;
pMatch = p;
}else if( p->iHold<iMinHold ){
iMinHold = p->iHold;
iMinKey = iKey;
}
if( p->iHold>iMaxHold ){
iMaxHold = p->iHold;
}
}
if( pMatch ){
pMatch->nErr = 0;
pMatch->iHold = iMaxHold+1;
return pMatch;
}
p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
if( p==0 ){
sqlite3_result_error_nomem(pCtx);
return 0;
}
memset(p, 0, sizeof(*p));
p->zJson = (char*)&p[1];
memcpy((char*)p->zJson, zJson, nJson+1);
if( jsonParse(p, pErrCtx, p->zJson) ){
if( pErrCtx==0 ){
p->nErr = 1;
return p;
}
sqlite3_free(p);
return 0;
}
p->nJson = nJson;
p->iHold = iMaxHold+1;
sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
(void(*)(void*))jsonParseFree);
return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
}
static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
if( pNode->n!=nKey ) return 0;
return strncmp(pNode->u.zJContent, zKey, nKey)==0;
}else{
if( pNode->n!=nKey+2 ) return 0;
return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
}
}
static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
if( p1->jnFlags & JNODE_RAW ){
return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
}else if( p2->jnFlags & JNODE_RAW ){
return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
}else{
return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
}
}
static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
static JsonNode *jsonLookupStep(
JsonParse *pParse,
u32 iRoot,
const char *zPath,
int *pApnd,
const char **pzErr
){
u32 i, j, nKey;
const char *zKey;
JsonNode *pRoot = &pParse->aNode[iRoot];
if( zPath[0]==0 ) return pRoot;
if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
if( zPath[0]=='.' ){
if( pRoot->eType!=JSON_OBJECT ) return 0;
zPath++;
if( zPath[0]=='"' ){
zKey = zPath + 1;
for(i=1; zPath[i] && zPath[i]!='"'; i++){}
nKey = i-1;
if( zPath[i] ){
i++;
}else{
*pzErr = zPath;
return 0;
}
testcase( nKey==0 );
}else{
zKey = zPath;
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
nKey = i;
if( nKey==0 ){
*pzErr = zPath;
return 0;
}
}
j = 1;
for(;;){
while( j<=pRoot->n ){
if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
}
j++;
j += jsonNodeSize(&pRoot[j]);
}
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
assert( pRoot->eU==2 );
iRoot += pRoot->u.iAppend;
pRoot = &pParse->aNode[iRoot];
j = 1;
}
if( pApnd ){
u32 iStart, iLabel;
JsonNode *pNode;
iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
zPath += i;
pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
if( pParse->oom ) return 0;
if( pNode ){
pRoot = &pParse->aNode[iRoot];
assert( pRoot->eU==0 );
pRoot->u.iAppend = iStart - iRoot;
pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 );
pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
}
return pNode;
}
}else if( zPath[0]=='[' ){
i = 0;
j = 1;
while( sqlite3Isdigit(zPath[j]) ){
i = i*10 + zPath[j] - '0';
j++;
}
if( j<2 || zPath[j]!=']' ){
if( zPath[1]=='#' ){
JsonNode *pBase = pRoot;
int iBase = iRoot;
if( pRoot->eType!=JSON_ARRAY ) return 0;
for(;;){
while( j<=pBase->n ){
if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
j += jsonNodeSize(&pBase[j]);
}
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
assert( pBase->eU==2 );
iBase += pBase->u.iAppend;
pBase = &pParse->aNode[iBase];
j = 1;
}
j = 2;
if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
unsigned int x = 0;
j = 3;
do{
x = x*10 + zPath[j] - '0';
j++;
}while( sqlite3Isdigit(zPath[j]) );
if( x>i ) return 0;
i -= x;
}
if( zPath[j]!=']' ){
*pzErr = zPath;
return 0;
}
}else{
*pzErr = zPath;
return 0;
}
}
if( pRoot->eType!=JSON_ARRAY ) return 0;
zPath += j + 1;
j = 1;
for(;;){
while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
j += jsonNodeSize(&pRoot[j]);
}
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
assert( pRoot->eU==2 );
iRoot += pRoot->u.iAppend;
pRoot = &pParse->aNode[iRoot];
j = 1;
}
if( j<=pRoot->n ){
return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
}
if( i==0 && pApnd ){
u32 iStart;
JsonNode *pNode;
iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
if( pParse->oom ) return 0;
if( pNode ){
pRoot = &pParse->aNode[iRoot];
assert( pRoot->eU==0 );
pRoot->u.iAppend = iStart - iRoot;
pRoot->jnFlags |= JNODE_APPEND;
VVA( pRoot->eU = 2 );
}
return pNode;
}
}else{
*pzErr = zPath;
}
return 0;
}
static JsonNode *jsonLookupAppend(
JsonParse *pParse,
const char *zPath,
int *pApnd,
const char **pzErr
){
*pApnd = 1;
if( zPath[0]==0 ){
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
}
if( zPath[0]=='.' ){
jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
}else if( strncmp(zPath,"[0]",3)==0 ){
jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
}else{
return 0;
}
if( pParse->oom ) return 0;
return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
}
static char *jsonPathSyntaxError(const char *zErr){
return sqlite3_mprintf("JSON path error near '%q'", zErr);
}
static JsonNode *jsonLookup(
JsonParse *pParse,
const char *zPath,
int *pApnd,
sqlite3_context *pCtx
){
const char *zErr = 0;
JsonNode *pNode = 0;
char *zMsg;
if( zPath==0 ) return 0;
if( zPath[0]!='$' ){
zErr = zPath;
goto lookup_err;
}
zPath++;
pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
if( zErr==0 ) return pNode;
lookup_err:
pParse->nErr++;
assert( zErr!=0 && pCtx!=0 );
zMsg = jsonPathSyntaxError(zErr);
if( zMsg ){
sqlite3_result_error(pCtx, zMsg, -1);
sqlite3_free(zMsg);
}else{
sqlite3_result_error_nomem(pCtx);
}
return 0;
}
static void jsonWrongNumArgs(
sqlite3_context *pCtx,
const char *zFuncName
){
char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
zFuncName);
sqlite3_result_error(pCtx, zMsg, -1);
sqlite3_free(zMsg);
}
static void jsonRemoveAllNulls(JsonNode *pNode){
int i, n;
assert( pNode->eType==JSON_OBJECT );
n = pNode->n;
for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
switch( pNode[i].eType ){
case JSON_NULL:
pNode[i].jnFlags |= JNODE_REMOVE;
break;
case JSON_OBJECT:
jsonRemoveAllNulls(&pNode[i]);
break;
}
}
}
#ifdef SQLITE_DEBUG
static void jsonParseFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonString s;
JsonParse x;
u32 i;
assert( argc==1 );
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
jsonParseFindParents(&x);
jsonInit(&s, ctx);
for(i=0; i<x.nNode; i++){
const char *zType;
if( x.aNode[i].jnFlags & JNODE_LABEL ){
assert( x.aNode[i].eType==JSON_STRING );
zType = "label";
}else{
zType = jsonType[x.aNode[i].eType];
}
jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
i, zType, x.aNode[i].n, x.aUp[i]);
assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
if( x.aNode[i].u.zJContent!=0 ){
assert( x.aNode[i].eU==1 );
jsonAppendRaw(&s, " ", 1);
jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
}else{
assert( x.aNode[i].eU==0 );
}
jsonAppendRaw(&s, "\n", 1);
}
jsonParseReset(&x);
jsonResult(&s);
}
static void jsonTest1Func(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
}
#endif
static void jsonQuoteFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonString jx;
UNUSED_PARAMETER(argc);
jsonInit(&jx, ctx);
jsonAppendValue(&jx, argv[0]);
jsonResult(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonArrayFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
int i;
JsonString jx;
jsonInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
jsonAppendValue(&jx, argv[i]);
}
jsonAppendChar(&jx, ']');
jsonResult(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonArrayLengthFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse *p;
sqlite3_int64 n = 0;
u32 i;
JsonNode *pNode;
p = jsonParseCached(ctx, argv, ctx);
if( p==0 ) return;
assert( p->nNode );
if( argc==2 ){
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
pNode = jsonLookup(p, zPath, 0, ctx);
}else{
pNode = p->aNode;
}
if( pNode==0 ){
return;
}
if( pNode->eType==JSON_ARRAY ){
assert( (pNode->jnFlags & JNODE_APPEND)==0 );
for(i=1; i<=pNode->n; n++){
i += jsonNodeSize(&pNode[i]);
}
}
sqlite3_result_int64(ctx, n);
}
#define JSON_JSON 0x01
#define JSON_SQL 0x02
#define JSON_ABPATH 0x03
#define JSON_ISSET 0x04
static void jsonExtractFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse *p;
JsonNode *pNode;
const char *zPath;
int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
JsonString jx;
if( argc<2 ) return;
p = jsonParseCached(ctx, argv, ctx);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)sqlite3_value_text(argv[1]);
if( zPath==0 ) return;
if( flags & JSON_ABPATH ){
if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){
jsonInit(&jx, ctx);
if( sqlite3Isdigit(zPath[0]) ){
jsonAppendRaw(&jx, "$[", 2);
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
jsonAppendRaw(&jx, "]", 2);
}else{
jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
jsonAppendChar(&jx, 0);
}
pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
jsonReset(&jx);
}else{
pNode = jsonLookup(p, zPath, 0, ctx);
}
if( pNode ){
if( flags & JSON_JSON ){
jsonReturnJson(pNode, ctx, 0);
}else{
jsonReturn(pNode, ctx, 0);
sqlite3_result_subtype(ctx, 0);
}
}
}else{
pNode = jsonLookup(p, zPath, 0, ctx);
if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
}
}else{
int i;
jsonInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=1; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
pNode = jsonLookup(p, zPath, 0, ctx);
if( p->nErr ) break;
jsonAppendSeparator(&jx);
if( pNode ){
jsonRenderNode(pNode, &jx, 0);
}else{
jsonAppendRaw(&jx, "null", 4);
}
}
if( i==argc ){
jsonAppendChar(&jx, ']');
jsonResult(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
jsonReset(&jx);
}
}
static JsonNode *jsonMergePatch(
JsonParse *pParse,
u32 iTarget,
JsonNode *pPatch
){
u32 i, j;
u32 iRoot;
JsonNode *pTarget;
if( pPatch->eType!=JSON_OBJECT ){
return pPatch;
}
assert( iTarget<pParse->nNode );
pTarget = &pParse->aNode[iTarget];
assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
if( pTarget->eType!=JSON_OBJECT ){
jsonRemoveAllNulls(pPatch);
return pPatch;
}
iRoot = iTarget;
for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
u32 nKey;
const char *zKey;
assert( pPatch[i].eType==JSON_STRING );
assert( pPatch[i].jnFlags & JNODE_LABEL );
assert( pPatch[i].eU==1 );
nKey = pPatch[i].n;
zKey = pPatch[i].u.zJContent;
for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
assert( pTarget[j].eType==JSON_STRING );
assert( pTarget[j].jnFlags & JNODE_LABEL );
if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){
if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
if( pPatch[i+1].eType==JSON_NULL ){
pTarget[j+1].jnFlags |= JNODE_REMOVE;
}else{
JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
if( pNew==0 ) return 0;
pTarget = &pParse->aNode[iTarget];
if( pNew!=&pTarget[j+1] ){
assert( pTarget[j+1].eU==0
|| pTarget[j+1].eU==1
|| pTarget[j+1].eU==2 );
testcase( pTarget[j+1].eU==1 );
testcase( pTarget[j+1].eU==2 );
VVA( pTarget[j+1].eU = 5 );
pTarget[j+1].u.pPatch = pNew;
pTarget[j+1].jnFlags |= JNODE_PATCH;
}
}
break;
}
}
if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
int iStart, iPatch;
iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
if( pParse->oom ) return 0;
jsonRemoveAllNulls(pPatch);
pTarget = &pParse->aNode[iTarget];
assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
testcase( pParse->aNode[iRoot].eU==2 );
pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
VVA( pParse->aNode[iRoot].eU = 2 );
pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
iRoot = iStart;
assert( pParse->aNode[iPatch].eU==0 );
VVA( pParse->aNode[iPatch].eU = 5 );
pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
}
}
return pTarget;
}
static void jsonPatchFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x;
JsonParse y;
JsonNode *pResult;
UNUSED_PARAMETER(argc);
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
jsonParseReset(&x);
return;
}
pResult = jsonMergePatch(&x, 0, y.aNode);
assert( pResult!=0 || x.oom );
if( pResult ){
jsonReturnJson(pResult, ctx, 0);
}else{
sqlite3_result_error_nomem(ctx);
}
jsonParseReset(&x);
jsonParseReset(&y);
}
static void jsonObjectFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
int i;
JsonString jx;
const char *z;
u32 n;
if( argc&1 ){
sqlite3_result_error(ctx, "json_object() requires an even number "
"of arguments", -1);
return;
}
jsonInit(&jx, ctx);
jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){
if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
jsonReset(&jx);
return;
}
jsonAppendSeparator(&jx);
z = (const char*)sqlite3_value_text(argv[i]);
n = (u32)sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':');
jsonAppendValue(&jx, argv[i+1]);
}
jsonAppendChar(&jx, '}');
jsonResult(&jx);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonRemoveFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x;
JsonNode *pNode;
const char *zPath;
u32 i;
if( argc<1 ) return;
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
assert( x.nNode );
for(i=1; i<(u32)argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
if( zPath==0 ) goto remove_done;
pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) goto remove_done;
if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
}
if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
jsonReturnJson(x.aNode, ctx, 0);
}
remove_done:
jsonParseReset(&x);
}
static void jsonReplaceFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x;
JsonNode *pNode;
const char *zPath;
u32 i;
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, "replace");
return;
}
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
assert( x.nNode );
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) goto replace_err;
if( pNode ){
assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
testcase( pNode->eU!=0 && pNode->eU!=1 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
VVA( pNode->eU = 4 );
pNode->u.iReplace = i + 1;
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
assert( x.aNode[0].eU==4 );
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
}else{
jsonReturnJson(x.aNode, ctx, argv);
}
replace_err:
jsonParseReset(&x);
}
static void jsonSetFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse x;
JsonNode *pNode;
const char *zPath;
u32 i;
int bApnd;
int bIsSet = sqlite3_user_data(ctx)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
assert( x.nNode );
for(i=1; i<(u32)argc; i+=2){
zPath = (const char*)sqlite3_value_text(argv[i]);
bApnd = 0;
pNode = jsonLookup(&x, zPath, &bApnd, ctx);
if( x.oom ){
sqlite3_result_error_nomem(ctx);
goto jsonSetDone;
}else if( x.nErr ){
goto jsonSetDone;
}else if( pNode && (bApnd || bIsSet) ){
testcase( pNode->eU!=0 && pNode->eU!=1 );
assert( pNode->eU!=3 && pNode->eU!=5 );
VVA( pNode->eU = 4 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
pNode->u.iReplace = i + 1;
}
}
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
assert( x.aNode[0].eU==4 );
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
}else{
jsonReturnJson(x.aNode, ctx, argv);
}
jsonSetDone:
jsonParseReset(&x);
}
static void jsonTypeFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse *p;
const char *zPath;
JsonNode *pNode;
p = jsonParseCached(ctx, argv, ctx);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)sqlite3_value_text(argv[1]);
pNode = jsonLookup(p, zPath, 0, ctx);
}else{
pNode = p->aNode;
}
if( pNode ){
sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
}
}
static void jsonValidFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse *p;
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
p = jsonParseCached(ctx, argv, 0);
if( p==0 || p->oom ){
sqlite3_result_error_nomem(ctx);
sqlite3_free(p);
}else{
sqlite3_result_int(ctx, p->nErr==0 && p->hasNonstd==0);
if( p->nErr ) jsonParseFree(p);
}
}
static void jsonErrorFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonParse *p;
UNUSED_PARAMETER(argc);
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
p = jsonParseCached(ctx, argv, 0);
if( p==0 || p->oom ){
sqlite3_result_error_nomem(ctx);
sqlite3_free(p);
}else if( p->nErr==0 ){
sqlite3_result_int(ctx, 0);
}else{
int n = 1;
u32 i;
const char *z = p->zJson;
for(i=0; i<p->iErr && ALWAYS(z[i]); i++){
if( (z[i]&0xc0)!=0x80 ) n++;
}
sqlite3_result_int(ctx, n);
jsonParseFree(p);
}
}
static void jsonArrayStep(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonString *pStr;
UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
jsonInit(pStr, ctx);
jsonAppendChar(pStr, '[');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
jsonAppendValue(pStr, argv[0]);
}
}
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
if( pStr->bErr ){
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
pStr->nUsed--;
}
}else{
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
}
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonArrayValue(sqlite3_context *ctx){
jsonArrayCompute(ctx, 0);
}
static void jsonArrayFinal(sqlite3_context *ctx){
jsonArrayCompute(ctx, 1);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void jsonGroupInverse(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
unsigned int i;
int inStr = 0;
int nNest = 0;
char *z;
char c;
JsonString *pStr;
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
for(i=1; i<pStr->nUsed && ((c = z[i])!=',' || inStr || nNest); i++){
if( c=='"' ){
inStr = !inStr;
}else if( c=='\\' ){
i++;
}else if( !inStr ){
if( c=='{' || c=='[' ) nNest++;
if( c=='}' || c==']' ) nNest--;
}
}
if( i<pStr->nUsed ){
pStr->nUsed -= i;
memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
z[pStr->nUsed] = 0;
}else{
pStr->nUsed = 1;
}
}
#else
# define jsonGroupInverse 0
#endif
static void jsonObjectStep(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
JsonString *pStr;
const char *z;
u32 n;
UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
jsonInit(pStr, ctx);
jsonAppendChar(pStr, '{');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
z = (const char*)sqlite3_value_text(argv[0]);
n = (u32)sqlite3_value_bytes(argv[0]);
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
jsonAppendValue(pStr, argv[1]);
}
}
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
jsonAppendChar(pStr, '}');
if( pStr->bErr ){
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
pStr->nUsed--;
}
}else{
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
}
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonObjectValue(sqlite3_context *ctx){
jsonObjectCompute(ctx, 0);
}
static void jsonObjectFinal(sqlite3_context *ctx){
jsonObjectCompute(ctx, 1);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef struct JsonEachCursor JsonEachCursor;
struct JsonEachCursor {
sqlite3_vtab_cursor base;
u32 iRowid;
u32 iBegin;
u32 i;
u32 iEnd;
u8 eType;
u8 bRecursive;
char *zJson;
char *zRoot;
JsonParse sParse;
};
static int jsonEachConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
sqlite3_vtab *pNew;
int rc;
#define JEACH_KEY 0
#define JEACH_VALUE 1
#define JEACH_TYPE 2
#define JEACH_ATOM 3
#define JEACH_ID 4
#define JEACH_PARENT 5
#define JEACH_FULLKEY 6
#define JEACH_PATH 7
#define JEACH_JSON 8
#define JEACH_ROOT 9
UNUSED_PARAMETER(pzErr);
UNUSED_PARAMETER(argv);
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(pAux);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
"json HIDDEN,root HIDDEN)");
if( rc==SQLITE_OK ){
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
if( pNew==0 ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
return rc;
}
static int jsonEachDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return SQLITE_OK;
}
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
JsonEachCursor *pCur;
UNUSED_PARAMETER(p);
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
*ppCursor = &pCur->base;
return SQLITE_OK;
}
static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
int rc = jsonEachOpenEach(p, ppCursor);
if( rc==SQLITE_OK ){
JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
pCur->bRecursive = 1;
}
return rc;
}
static void jsonEachCursorReset(JsonEachCursor *p){
sqlite3_free(p->zJson);
sqlite3_free(p->zRoot);
jsonParseReset(&p->sParse);
p->iRowid = 0;
p->i = 0;
p->iEnd = 0;
p->eType = 0;
p->zJson = 0;
p->zRoot = 0;
}
static int jsonEachClose(sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
jsonEachCursorReset(p);
sqlite3_free(cur);
return SQLITE_OK;
}
static int jsonEachEof(sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
return p->i >= p->iEnd;
}
static int jsonEachNext(sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
if( p->bRecursive ){
if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
p->i++;
p->iRowid++;
if( p->i<p->iEnd ){
u32 iUp = p->sParse.aUp[p->i];
JsonNode *pUp = &p->sParse.aNode[iUp];
p->eType = pUp->eType;
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==0 || pUp->eU==3 );
testcase( pUp->eU==3 );
VVA( pUp->eU = 3 );
if( iUp==p->i-1 ){
pUp->u.iKey = 0;
}else{
pUp->u.iKey++;
}
}
}
}else{
switch( p->eType ){
case JSON_ARRAY: {
p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
p->iRowid++;
break;
}
case JSON_OBJECT: {
p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
p->iRowid++;
break;
}
default: {
p->i = p->iEnd;
break;
}
}
}
return SQLITE_OK;
}
static void jsonAppendObjectPathElement(
JsonString *pStr,
JsonNode *pNode
){
int jj, nn;
const char *z;
assert( pNode->eType==JSON_STRING );
assert( pNode->jnFlags & JNODE_LABEL );
assert( pNode->eU==1 );
z = pNode->u.zJContent;
nn = pNode->n;
if( (pNode->jnFlags & JNODE_RAW)==0 ){
assert( nn>=2 );
assert( z[0]=='"' || z[0]=='\'' );
assert( z[nn-1]=='"' || z[0]=='\'' );
if( nn>2 && sqlite3Isalpha(z[1]) ){
for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
if( jj==nn-1 ){
z++;
nn -= 2;
}
}
}
jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
}
static void jsonEachComputePath(
JsonEachCursor *p,
JsonString *pStr,
u32 i
){
JsonNode *pNode, *pUp;
u32 iUp;
if( i==0 ){
jsonAppendChar(pStr, '$');
return;
}
iUp = p->sParse.aUp[i];
jsonEachComputePath(p, pStr, iUp);
pNode = &p->sParse.aNode[i];
pUp = &p->sParse.aNode[iUp];
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
testcase( pUp->eU==0 );
jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
}else{
assert( pUp->eType==JSON_OBJECT );
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
jsonAppendObjectPathElement(pStr, pNode);
}
}
static int jsonEachColumn(
sqlite3_vtab_cursor *cur,
sqlite3_context *ctx,
int i
){
JsonEachCursor *p = (JsonEachCursor*)cur;
JsonNode *pThis = &p->sParse.aNode[p->i];
switch( i ){
case JEACH_KEY: {
if( p->i==0 ) break;
if( p->eType==JSON_OBJECT ){
jsonReturn(pThis, ctx, 0);
}else if( p->eType==JSON_ARRAY ){
u32 iKey;
if( p->bRecursive ){
if( p->iRowid==0 ) break;
assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
}else{
iKey = p->iRowid;
}
sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
}
break;
}
case JEACH_VALUE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
jsonReturn(pThis, ctx, 0);
break;
}
case JEACH_TYPE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
if( pThis->eType>=JSON_ARRAY ) break;
jsonReturn(pThis, ctx, 0);
break;
}
case JEACH_ID: {
sqlite3_result_int64(ctx,
(sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
break;
}
case JEACH_PARENT: {
if( p->i>p->iBegin && p->bRecursive ){
sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
}
break;
}
case JEACH_FULLKEY: {
JsonString x;
jsonInit(&x, ctx);
if( p->bRecursive ){
jsonEachComputePath(p, &x, p->i);
}else{
if( p->zRoot ){
jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
}else{
jsonAppendChar(&x, '$');
}
if( p->eType==JSON_ARRAY ){
jsonPrintf(30, &x, "[%d]", p->iRowid);
}else if( p->eType==JSON_OBJECT ){
jsonAppendObjectPathElement(&x, pThis);
}
}
jsonResult(&x);
break;
}
case JEACH_PATH: {
if( p->bRecursive ){
JsonString x;
jsonInit(&x, ctx);
jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
jsonResult(&x);
break;
}
deliberate_fall_through
}
default: {
const char *zRoot = p->zRoot;
if( zRoot==0 ) zRoot = "$";
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
assert( i==JEACH_JSON );
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
break;
}
}
return SQLITE_OK;
}
static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
JsonEachCursor *p = (JsonEachCursor*)cur;
*pRowid = p->iRowid;
return SQLITE_OK;
}
static int jsonEachBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
int i;
int aIdx[2];
int unusableMask = 0;
int idxMask = 0;
const struct sqlite3_index_constraint *pConstraint;
assert( JEACH_ROOT == JEACH_JSON+1 );
UNUSED_PARAMETER(tab);
aIdx[0] = aIdx[1] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
int iCol;
int iMask;
if( pConstraint->iColumn < JEACH_JSON ) continue;
iCol = pConstraint->iColumn - JEACH_JSON;
assert( iCol==0 || iCol==1 );
testcase( iCol==0 );
iMask = 1 << iCol;
if( pConstraint->usable==0 ){
unusableMask |= iMask;
}else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
aIdx[iCol] = i;
idxMask |= iMask;
}
}
if( pIdxInfo->nOrderBy>0
&& pIdxInfo->aOrderBy[0].iColumn<0
&& pIdxInfo->aOrderBy[0].desc==0
){
pIdxInfo->orderByConsumed = 1;
}
if( (unusableMask & ~idxMask)!=0 ){
return SQLITE_CONSTRAINT;
}
if( aIdx[0]<0 ){
pIdxInfo->idxNum = 0;
}else{
pIdxInfo->estimatedCost = 1.0;
i = aIdx[0];
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
pIdxInfo->aConstraintUsage[i].omit = 1;
if( aIdx[1]<0 ){
pIdxInfo->idxNum = 1;
}else{
i = aIdx[1];
pIdxInfo->aConstraintUsage[i].argvIndex = 2;
pIdxInfo->aConstraintUsage[i].omit = 1;
pIdxInfo->idxNum = 3;
}
}
return SQLITE_OK;
}
static int jsonEachFilter(
sqlite3_vtab_cursor *cur,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
JsonEachCursor *p = (JsonEachCursor*)cur;
const char *z;
const char *zRoot = 0;
sqlite3_int64 n;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
z = (const char*)sqlite3_value_text(argv[0]);
if( z==0 ) return SQLITE_OK;
n = sqlite3_value_bytes(argv[0]);
p->zJson = sqlite3_malloc64( n+1 );
if( p->zJson==0 ) return SQLITE_NOMEM;
memcpy(p->zJson, z, (size_t)n+1);
if( jsonParse(&p->sParse, 0, p->zJson) ){
int rc = SQLITE_NOMEM;
if( p->sParse.oom==0 ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
}
jsonEachCursorReset(p);
return rc;
}else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
jsonEachCursorReset(p);
return SQLITE_NOMEM;
}else{
JsonNode *pNode = 0;
if( idxNum==3 ){
const char *zErr = 0;
zRoot = (const char*)sqlite3_value_text(argv[1]);
if( zRoot==0 ) return SQLITE_OK;
n = sqlite3_value_bytes(argv[1]);
p->zRoot = sqlite3_malloc64( n+1 );
if( p->zRoot==0 ) return SQLITE_NOMEM;
memcpy(p->zRoot, zRoot, (size_t)n+1);
if( zRoot[0]!='$' ){
zErr = zRoot;
}else{
pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
}
if( zErr ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}else if( pNode==0 ){
return SQLITE_OK;
}
}else{
pNode = p->sParse.aNode;
}
p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
p->eType = pNode->eType;
if( p->eType>=JSON_ARRAY ){
assert( pNode->eU==0 );
VVA( pNode->eU = 3 );
pNode->u.iKey = 0;
p->iEnd = p->i + pNode->n + 1;
if( p->bRecursive ){
p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
p->i--;
}
}else{
p->i++;
}
}else{
p->iEnd = p->i+1;
}
}
return SQLITE_OK;
}
static sqlite3_module jsonEachModule = {
0,
0,
jsonEachConnect,
jsonEachBestIndex,
jsonEachDisconnect,
0,
jsonEachOpenEach,
jsonEachClose,
jsonEachFilter,
jsonEachNext,
jsonEachEof,
jsonEachColumn,
jsonEachRowid,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
static sqlite3_module jsonTreeModule = {
0,
0,
jsonEachConnect,
jsonEachBestIndex,
jsonEachDisconnect,
0,
jsonEachOpenTree,
jsonEachClose,
jsonEachFilter,
jsonEachNext,
jsonEachEof,
jsonEachColumn,
jsonEachRowid,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
#endif
#endif
void sqlite3RegisterJsonFunctions(void){
#ifndef SQLITE_OMIT_JSON
static FuncDef aJsonFunc[] = {
JFUNCTION(json, 1, 0, jsonRemoveFunc),
JFUNCTION(json_array, -1, 0, jsonArrayFunc),
JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
JFUNCTION(json_error_position,1, 0, jsonErrorFunc),
JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
JFUNCTION(json_insert, -1, 0, jsonSetFunc),
JFUNCTION(json_object, -1, 0, jsonObjectFunc),
JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
JFUNCTION(json_type, 1, 0, jsonTypeFunc),
JFUNCTION(json_type, 2, 0, jsonTypeFunc),
JFUNCTION(json_valid, 1, 0, jsonValidFunc),
#if SQLITE_DEBUG
JFUNCTION(json_parse, 1, 0, jsonParseFunc),
JFUNCTION(json_test1, 1, 0, jsonTest1Func),
#endif
WAGGREGATE(json_group_array, 1, 0, 0,
jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
WAGGREGATE(json_group_object, 2, 0, 0,
jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC)
};
sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
}
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
int sqlite3JsonTableFunctions(sqlite3 *db){
int rc = SQLITE_OK;
static const struct {
const char *zName;
sqlite3_module *pModule;
} aMod[] = {
{ "json_each", &jsonEachModule },
{ "json_tree", &jsonTreeModule },
};
unsigned int i;
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
}
return rc;
}
#endif