Index: third_party/sqlite/src/ext/misc/json1.c |
diff --git a/third_party/sqlite/src/ext/misc/json1.c b/third_party/sqlite/src/ext/misc/json1.c |
index 37075166607289b5b56887ab29337571d63644df..3063f9f261a8bbb365853bbf1a53dddb94662fd2 100644 |
--- a/third_party/sqlite/src/ext/misc/json1.c |
+++ b/third_party/sqlite/src/ext/misc/json1.c |
@@ -22,7 +22,7 @@ |
** how JSONB might improve on that.) |
*/ |
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) |
-#if !defined(_SQLITEINT_H_) |
+#if !defined(SQLITEINT_H) |
#include "sqlite3ext.h" |
#endif |
SQLITE_EXTENSION_INIT1 |
@@ -31,7 +31,11 @@ SQLITE_EXTENSION_INIT1 |
#include <stdlib.h> |
#include <stdarg.h> |
-#define UNUSED_PARAM(X) (void)(X) |
+/* Mark a function parameter as unused, to suppress nuisance compiler |
+** warnings. */ |
+#ifndef UNUSED_PARAM |
+# define UNUSED_PARAM(X) (void)(X) |
+#endif |
#ifndef LARGEST_INT64 |
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32)) |
@@ -45,13 +49,15 @@ SQLITE_EXTENSION_INIT1 |
#ifdef sqlite3Isdigit |
/* Use the SQLite core versions if this routine is part of the |
** SQLite amalgamation */ |
-# define safe_isdigit(x) sqlite3Isdigit(x) |
-# define safe_isalnum(x) sqlite3Isalnum(x) |
+# define safe_isdigit(x) sqlite3Isdigit(x) |
+# define safe_isalnum(x) sqlite3Isalnum(x) |
+# define safe_isxdigit(x) sqlite3Isxdigit(x) |
#else |
/* Use the standard library for separate compilation */ |
#include <ctype.h> /* amalgamator: keep */ |
-# define safe_isdigit(x) isdigit((unsigned char)(x)) |
-# define safe_isalnum(x) isalnum((unsigned char)(x)) |
+# define safe_isdigit(x) isdigit((unsigned char)(x)) |
+# define safe_isalnum(x) isalnum((unsigned char)(x)) |
+# define safe_isxdigit(x) isxdigit((unsigned char)(x)) |
#endif |
/* |
@@ -276,10 +282,33 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ |
if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; |
p->zBuf[p->nUsed++] = '"'; |
for(i=0; i<N; i++){ |
- char c = zIn[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; |
} |
@@ -320,7 +349,7 @@ static void jsonAppendValue( |
default: { |
if( p->bErr==0 ){ |
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
- p->bErr = 1; |
+ p->bErr = 2; |
jsonReset(p); |
} |
break; |
@@ -566,12 +595,13 @@ static void jsonReturn( |
c = z[++i]; |
if( c=='u' ){ |
u32 v = 0, k; |
- for(k=0; k<4 && i<n-2; i++, k++){ |
+ for(k=0; k<4; i++, k++){ |
+ assert( i<n-2 ); |
c = z[i+1]; |
- if( c>='0' && c<='9' ) v = v*16 + c - '0'; |
- else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10; |
- else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10; |
- else break; |
+ assert( safe_isxdigit(c) ); |
+ if( c<='9' ) v = v*16 + c - '0'; |
+ else if( c<='F' ) v = v*16 + c - 'A' + 10; |
+ else v = v*16 + c - 'a' + 10; |
} |
if( v==0 ) break; |
if( v<=0x7f ){ |
@@ -676,6 +706,15 @@ static int jsonParseAddNode( |
} |
/* |
+** Return true if z[] begins with 4 (or more) hexadecimal digits |
+*/ |
+static int jsonIs4Hex(const char *z){ |
+ int i; |
+ for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; |
+ return 1; |
+} |
+ |
+/* |
** Parse a single JSON value which begins at pParse->zJson[i]. Return the |
** index of the first character past the end of the value parsed. |
** |
@@ -749,8 +788,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ |
if( c==0 ) return -1; |
if( c=='\\' ){ |
c = pParse->zJson[++j]; |
- if( c==0 ) return -1; |
- jnFlags = JNODE_ESCAPE; |
+ if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' |
+ || c=='n' || c=='r' || c=='t' |
+ || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){ |
+ jnFlags = JNODE_ESCAPE; |
+ }else{ |
+ return -1; |
+ } |
}else if( c=='"' ){ |
break; |
} |
@@ -1185,6 +1229,26 @@ static void jsonTest1Func( |
****************************************************************************/ |
/* |
+** Implementation of the json_QUOTE(VALUE) function. Return a JSON value |
+** corresponding to the SQL value input. Mostly this means putting |
+** double-quotes around strings and returning the unquoted string "null" |
+** when given a NULL input. |
+*/ |
+static void jsonQuoteFunc( |
+ sqlite3_context *ctx, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ JsonString jx; |
+ UNUSED_PARAM(argc); |
+ |
+ jsonInit(&jx, ctx); |
+ jsonAppendValue(&jx, argv[0]); |
+ jsonResult(&jx); |
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE); |
+} |
+ |
+/* |
** Implementation of the json_array(VALUE,...) function. Return a JSON |
** array that contains all values given in arguments. Or if any argument |
** is a BLOB, throw an error. |
@@ -1529,6 +1593,7 @@ static void jsonArrayStep( |
sqlite3_value **argv |
){ |
JsonString *pStr; |
+ UNUSED_PARAM(argc); |
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); |
if( pStr ){ |
if( pStr->zBuf==0 ){ |
@@ -1548,7 +1613,7 @@ static void jsonArrayFinal(sqlite3_context *ctx){ |
pStr->pCtx = ctx; |
jsonAppendChar(pStr, ']'); |
if( pStr->bErr ){ |
- sqlite3_result_error_nomem(ctx); |
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
assert( pStr->bStatic ); |
}else{ |
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, |
@@ -1574,6 +1639,7 @@ static void jsonObjectStep( |
JsonString *pStr; |
const char *z; |
u32 n; |
+ UNUSED_PARAM(argc); |
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr)); |
if( pStr ){ |
if( pStr->zBuf==0 ){ |
@@ -1596,7 +1662,7 @@ static void jsonObjectFinal(sqlite3_context *ctx){ |
if( pStr ){ |
jsonAppendChar(pStr, '}'); |
if( pStr->bErr ){ |
- sqlite3_result_error_nomem(ctx); |
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
assert( pStr->bStatic ); |
}else{ |
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, |
@@ -1874,9 +1940,9 @@ static int jsonEachColumn( |
/* For json_each() path and root are the same so fall through |
** into the root case */ |
} |
- case JEACH_ROOT: { |
+ default: { |
const char *zRoot = p->zRoot; |
- if( zRoot==0 ) zRoot = "$"; |
+ if( zRoot==0 ) zRoot = "$"; |
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); |
break; |
} |
@@ -2095,6 +2161,7 @@ int sqlite3Json1Init(sqlite3 *db){ |
{ "json_extract", -1, 0, jsonExtractFunc }, |
{ "json_insert", -1, 0, jsonSetFunc }, |
{ "json_object", -1, 0, jsonObjectFunc }, |
+ { "json_quote", 1, 0, jsonQuoteFunc }, |
{ "json_remove", -1, 0, jsonRemoveFunc }, |
{ "json_replace", -1, 0, jsonReplaceFunc }, |
{ "json_set", -1, 1, jsonSetFunc }, |