aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/misc/json1.c89
-rw-r--r--manifest28
-rw-r--r--manifest.uuid2
-rw-r--r--src/loadext.c5
-rw-r--r--src/sqlite.h.in30
-rw-r--r--src/sqlite3ext.h6
-rw-r--r--src/test_func.c33
-rw-r--r--src/vdbeInt.h1
-rw-r--r--src/vdbeapi.c7
-rw-r--r--test/json101.test18
-rw-r--r--test/subtype1.test31
11 files changed, 169 insertions, 81 deletions
diff --git a/ext/misc/json1.c b/ext/misc/json1.c
index 755d035c3..a217ce80b 100644
--- a/ext/misc/json1.c
+++ b/ext/misc/json1.c
@@ -68,6 +68,9 @@ struct JsonString {
#define JSON_ARRAY 6
#define JSON_OBJECT 7
+/* The "subtype" set for JSON values */
+#define JSON_SUBTYPE 74 /* Ascii for "J" */
+
/*
** Names of the various JSON types:
*/
@@ -82,8 +85,7 @@ static const char * const jsonType[] = {
#define JNODE_REMOVE 0x04 /* Do not output */
#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */
#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_JSON 0x20 /* Treat REPLACE as JSON text */
-#define JNODE_LABEL 0x40 /* Is a label of an object */
+#define JNODE_LABEL 0x20 /* Is a label of an object */
/* A single node of parsed JSON
@@ -243,8 +245,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
*/
static void jsonAppendValue(
JsonString *p, /* Append to this JSON string */
- sqlite3_value *pValue, /* Value to append */
- u8 textIsJson /* Try to treat text values as JSON */
+ sqlite3_value *pValue /* Value to append */
){
switch( sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
@@ -261,7 +262,7 @@ static void jsonAppendValue(
case SQLITE_TEXT: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
- if( textIsJson ){
+ if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
jsonAppendRaw(p, z, n);
}else{
jsonAppendString(p, z, n);
@@ -365,8 +366,7 @@ static void jsonRenderNode(
if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
if( pNode[j].jnFlags & JNODE_REPLACE ){
jsonAppendSeparator(pOut);
- jsonAppendValue(pOut, aReplace[pNode[j].iVal],
- (pNode[j].jnFlags & JNODE_JSON)!=0);
+ jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
}
}else{
jsonAppendSeparator(pOut);
@@ -391,8 +391,7 @@ static void jsonRenderNode(
jsonRenderNode(&pNode[j], pOut, aReplace);
jsonAppendChar(pOut, ':');
if( pNode[j+1].jnFlags & JNODE_REPLACE ){
- jsonAppendValue(pOut, aReplace[pNode[j+1].iVal],
- (pNode[j+1].jnFlags & JNODE_JSON)!=0);
+ jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
}else{
jsonRenderNode(&pNode[j+1], pOut, aReplace);
}
@@ -421,6 +420,7 @@ static void jsonReturnJson(
jsonInit(&s, pCtx);
jsonRenderNode(pNode, &s, aReplace);
jsonResult(&s);
+ sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
}
/*
@@ -951,21 +951,15 @@ static char *jsonPathSyntaxError(const char *zErr){
**
** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
** nodes are appended.
-**
-** If the path starts with $$ then set *pFlags to JNODE_REPLACE|JNODE_JSON
-** as a single to the caller that the input text to be inserted should be
-** interpreted as JSON rather than as ordinary text.
*/
static JsonNode *jsonLookup(
JsonParse *pParse, /* The JSON to search */
const char *zPath, /* The path to search */
int *pApnd, /* Append nodes to complete path if not NULL */
- sqlite3_context *pCtx, /* Report errors here, if not NULL */
- u8 *pFlags /* Write JNODE_REPLACE or _REPLACE|_JSON here */
+ sqlite3_context *pCtx /* Report errors here, if not NULL */
){
const char *zErr = 0;
JsonNode *pNode = 0;
- u8 fg = JNODE_REPLACE;
if( zPath==0 ) return 0;
if( zPath[0]!='$' ){
@@ -973,15 +967,6 @@ static JsonNode *jsonLookup(
goto lookup_err;
}
zPath++;
- if( zPath[0]=='$' ){
- if( pFlags==0 ){
- zErr = zPath;
- goto lookup_err;
- }
- zPath++;
- fg = JNODE_REPLACE|JNODE_JSON;
- }
- if( pFlags ) *pFlags = fg;
pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
return pNode;
@@ -996,7 +981,6 @@ lookup_err:
sqlite3_result_error_nomem(pCtx);
}
}
- if( pFlags ) *pFlags = fg;
return 0;
}
@@ -1060,32 +1044,16 @@ static void jsonParseFunc(
}
/*
-** The json_test1(JSON) function parses and rebuilds the JSON string.
+** The json_test1(JSON) function return true (1) if the input is JSON
+** text generated by another json function. It returns (0) if the input
+** is not known to be JSON.
*/
static void jsonTest1Func(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonReturnJson(x.aNode, ctx, 0);
- jsonParseReset(&x);
-}
-
-/*
-** The json_nodecount(JSON) function returns the number of nodes in the
-** input JSON string.
-*/
-static void jsonNodeCountFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- sqlite3_result_int64(ctx, (sqlite3_int64)x.nNode);
- jsonParseReset(&x);
+ sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
}
#endif /* SQLITE_DEBUG */
@@ -1110,10 +1078,11 @@ static void jsonArrayFunc(
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i], 0);
+ jsonAppendValue(&jx, argv[i]);
}
jsonAppendChar(&jx, ']');
jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -1138,7 +1107,7 @@ static void jsonArrayLengthFunc(
JsonNode *pNode;
if( argc==2 ){
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
}else{
pNode = x.aNode;
}
@@ -1180,7 +1149,7 @@ static void jsonExtractFunc(
jsonAppendChar(&jx, '[');
for(i=1; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) break;
if( argc>2 ){
jsonAppendSeparator(&jx);
@@ -1196,6 +1165,7 @@ static void jsonExtractFunc(
if( argc>2 && i==argc ){
jsonAppendChar(&jx, ']');
jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
jsonReset(&jx);
jsonParseReset(&x);
@@ -1234,10 +1204,11 @@ static void jsonObjectFunc(
n = (u32)sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1], 0);
+ jsonAppendValue(&jx, argv[i+1]);
}
jsonAppendChar(&jx, '}');
jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -1263,7 +1234,7 @@ static void jsonRemoveFunc(
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, 0);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) goto remove_done;
if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
}
@@ -1299,13 +1270,11 @@ static void jsonReplaceFunc(
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( x.nNode ){
for(i=1; i<(u32)argc; i+=2){
- u8 jnFlags = JNODE_REPLACE;
zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx, &jnFlags);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
if( x.nErr ) goto replace_err;
if( pNode ){
- pNode->jnFlags &= ~JNODE_JSON;
- pNode->jnFlags |= jnFlags;
+ pNode->jnFlags |= JNODE_REPLACE;
pNode->iVal = i+1;
}
}
@@ -1351,18 +1320,16 @@ static void jsonSetFunc(
if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
if( x.nNode ){
for(i=1; i<(u32)argc; i+=2){
- u8 jnFlags = JNODE_REPLACE;
zPath = (const char*)sqlite3_value_text(argv[i]);
bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx, &jnFlags);
+ 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) ){
- pNode->jnFlags &= ~JNODE_JSON;
- pNode->jnFlags |= jnFlags;
+ pNode->jnFlags |= JNODE_REPLACE;
pNode->iVal = i+1;
}
}
@@ -1396,7 +1363,7 @@ static void jsonTypeFunc(
JsonNode *pNode;
if( argc==2 ){
zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx, 0);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
}else{
pNode = x.aNode;
}
@@ -1917,6 +1884,7 @@ int sqlite3_json_init(
int flag;
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFunc[] = {
+ { "json", 1, 0, jsonRemoveFunc },
{ "json_array", -1, 0, jsonArrayFunc },
{ "json_array_length", 1, 0, jsonArrayLengthFunc },
{ "json_array_length", 2, 0, jsonArrayLengthFunc },
@@ -1934,7 +1902,6 @@ int sqlite3_json_init(
/* DEBUG and TESTING functions */
{ "json_parse", 1, 0, jsonParseFunc },
{ "json_test1", 1, 0, jsonTest1Func },
- { "json_nodecount", 1, 0, jsonNodeCountFunc },
#endif
};
#ifndef SQLITE_OMIT_VIRTUALTABLE
diff --git a/manifest b/manifest
index 69a0154d2..3fc4b6ab3 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\spotential\sNULL\spointer\sderef\sin\sthe\stesting\slogic\sof\spcache1.\nNB:\sThe\s-DSQLITE_TEST\scompile-time\soption\sis\sneeded\sto\shit\sthe\sproblem.
-D 2015-09-10T19:22:25.531
+C Add\snew\sinterfaces\ssqlite3_value_subtype()\sand\ssqlite3_result_subtype().\nUpdate\sthe\sjson1.c\sextension\sto\stake\sadvantages\sof\sthose\sinterfaces\sto\savoid\nthe\sgoofy\s'$$'\spath\ssyntax\sand\sto\sallow\snested\scalls\sto\sjson_array()\sand\njson_object()\sthat\swork\sas\sexpected.
+D 2015-09-11T00:26:04.863
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -195,7 +195,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
-F ext/misc/json1.c 4387d091c0ec0f4d9ed05560960f03d366db4fe0
+F ext/misc/json1.c 96490b8e34299a416ab221f827e0369344d95c53
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
@@ -304,7 +304,7 @@ F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012
-F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2
+F src/loadext.c f0b66d28e377fd6c6d36cc9d92df1ff251ebee44
F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54
F src/malloc.c 3a37ce6979a40f499d8cea9e9ab4e8517854d35d
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
@@ -342,9 +342,9 @@ F src/resolve.c 3126f7694b8ce0f97282d7dd3a5198b8fa18dce9
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c c17613385bc6b095c421b1f30548814f5fd8a9b2
F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42
-F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00
+F src/sqlite.h.in 65ff1449e8c181da9ec752e8304e0a1efffaf47f
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
-F src/sqlite3ext.h 5088f0b63491677da848c0d07d5711781302d362
+F src/sqlite3ext.h 64350bf36833a56ad675e27392a913f417c5c308
F src/sqliteInt.h 788dc0ea7ba32ec9fec06c628c1792d7b4753d86
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
@@ -368,7 +368,7 @@ F src/test_config.c fb2e5d354d9a077f5fbb261652eff4787deb104f
F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
-F src/test_func.c f1ac201465472e76a73e2f3695c3553c63e7322a
+F src/test_func.c 0d9c25956152adefee8881c6fadc8354793764d0
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 66b33120ffe9cd853b5a905ec850d51151337b32
F src/test_intarray.c 870124b95ec4c645d4eb84f15efb7133528fb1a5
@@ -405,8 +405,8 @@ F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
F src/vdbe.c 6d85be995bd2308a5aa2a68c7b564c5d4cc1a6fb
F src/vdbe.h 4bc88bd0e06f8046ee6ab7487c0015e85ad949ad
-F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
-F src/vdbeapi.c b821d530bcb2900b4604cf5206f2177f3f881d15
+F src/vdbeInt.h 8b867eac234e28627ffcace3cd4b4b79bbec664b
+F src/vdbeapi.c 0d890f57caf143b114a95ce699e59af51359c508
F src/vdbeaux.c fd00b489ab3f44f2dca1e4344faf289b7bfcf649
F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a
F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915
@@ -814,7 +814,7 @@ F test/journal3.test ff8af941f9e06161d3db1b46bb9f965ff0e7f307
F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
-F test/json101.test 11535d8986184500f4c30cc2f0b154b4ab05cc4e
+F test/json101.test e20d2421c531db32fad59c5e06e80af0b1b002c8
F test/json102.test 12ef6d7d7c02c526fa3c2be1e933e7eb2a497cea
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
@@ -1036,6 +1036,7 @@ F test/subquery.test d7268d193dd33d5505df965399d3a594e76ae13f
F test/subquery2.test 438f8a7da1457277b22e4176510f7659b286995f
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
+F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
@@ -1385,7 +1386,8 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 0c0c4ae971e54efc526eed7bd071c90dfadb95ff
-R 3ba34701e76f91459126301401d510a6
+P f5580f08538636ffb1367e717a33756288ccddde 8a80d6459e246ec1b38325e1cbd1e862157138b3
+R 6298ef57aadddbd507dac61cb4572ea0
+T +closed 8a80d6459e246ec1b38325e1cbd1e862157138b3
U drh
-Z c5b1b6a1894a9ad25bccddfa15233f55
+Z 2fd3a23a70bcc4f4e537cdb3e485fd63
diff --git a/manifest.uuid b/manifest.uuid
index be02be366..1e2577e11 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-f5580f08538636ffb1367e717a33756288ccddde \ No newline at end of file
+db4152aef2253ed2a33e3cad01e0c6758e03f900 \ No newline at end of file
diff --git a/src/loadext.c b/src/loadext.c
index 1d398c54c..b4b981e54 100644
--- a/src/loadext.c
+++ b/src/loadext.c
@@ -407,7 +407,10 @@ static const sqlite3_api_routines sqlite3Apis = {
(sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
sqlite3_value_free,
sqlite3_result_zeroblob64,
- sqlite3_bind_zeroblob64
+ sqlite3_bind_zeroblob64,
+ /* Version 3.8.12 and later */
+ sqlite3_value_subtype,
+ sqlite3_result_subtype
};
/*
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index a7d6318e5..65a0bedb0 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -4358,6 +4358,22 @@ int sqlite3_value_type(sqlite3_value*);
int sqlite3_value_numeric_type(sqlite3_value*);
/*
+** CAPI3REF: Obtaining SQL Values
+** METHOD: sqlite3_value
+**
+** The sqlite3_value_subtype(V) function returns the subtype for
+** an application-defined SQL function argument V. The subtype
+** information can be used to pass a limited amount of context from
+** one SQL function to another. Use the [sqlite3_result_subtype()]
+** routine to set the subtype for the return value of an SQL function.
+**
+** SQLite makes no use of subtype itself. It merely passes the subtype
+** from the result of one application-defined function to the input of
+** another.
+*/
+unsigned int sqlite3_value_subtype(sqlite3_value*);
+
+/*
** CAPI3REF: Copy And Free SQL Values
** METHOD: sqlite3_value
**
@@ -4656,6 +4672,20 @@ void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
void sqlite3_result_zeroblob(sqlite3_context*, int n);
int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
+
+/*
+** CAPI3REF: Setting The Subtype Of An SQL Function
+** METHOD: sqlite3_context
+**
+** The sqlite3_result_subtype(C,T) function causes the subtype of
+** the result from the application-defined function with context C
+** to be T. Only the lower 8 bits of the subtype T are preserved
+** in current versions of SQLite; higher order bits are discarded.
+** The number of subtype bytes preserved by SQLite might increase
+** in future releases of SQLite.
+*/
+void sqlite3_result_subtype(sqlite3_context*,unsigned int);
+
/*
** CAPI3REF: Define New Collating Sequences
** METHOD: sqlite3
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 9c01241a1..9b9f610e9 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -272,6 +272,9 @@ struct sqlite3_api_routines {
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
+ /* Version 3.8.12 and later */
+ unsigned int (*value_subtype)(sqlite3_value*);
+ void (*result_subtype)(sqlite3_context*,unsigned int);
};
/*
@@ -508,6 +511,9 @@ struct sqlite3_api_routines {
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
+/* Version 3.8.12 and later */
+#define sqlite3_value_subtype sqlite3_api->value_subtype
+#define sqlite3_result_subtype sqlite3_api->result_subtype
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/test_func.c b/src/test_func.c
index 2e34fa074..63cf18e3f 100644
--- a/src/test_func.c
+++ b/src/test_func.c
@@ -462,7 +462,7 @@ static void real2hex(
}
/*
-** tclcmd: test_extract(record, field)
+** test_extract(record, field)
**
** This function implements an SQL user-function that accepts a blob
** containing a formatted database record as the first argument. The
@@ -509,7 +509,7 @@ static void test_extract(
}
/*
-** tclcmd: test_decode(record)
+** test_decode(record)
**
** This function implements an SQL user-function that accepts a blob
** containing a formatted database record as its only argument. It returns
@@ -601,6 +601,8 @@ static void test_decode(
}
/*
+** test_zeroblob(N)
+**
** The implementation of scalar SQL function "test_zeroblob()". This is
** similar to the built-in zeroblob() function, except that it does not
** check that the integer parameter is within range before passing it
@@ -615,6 +617,31 @@ static void test_zeroblob(
sqlite3_result_zeroblob(context, nZero);
}
+/* test_getsubtype(V)
+**
+** Return the subtype for value V.
+*/
+static void test_getsubtype(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_result_int(context, (int)sqlite3_value_subtype(argv[0]));
+}
+
+/* test_setsubtype(V, T)
+**
+** Return the value V with its subtype changed to T
+*/
+static void test_setsubtype(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_result_value(context, argv[0]);
+ sqlite3_result_subtype(context, (unsigned int)sqlite3_value_int(argv[1]));
+}
+
static int registerTestFunctions(sqlite3 *db){
static const struct {
char *zName;
@@ -641,6 +668,8 @@ static int registerTestFunctions(sqlite3 *db){
{ "test_decode", 1, SQLITE_UTF8, test_decode},
{ "test_extract", 2, SQLITE_UTF8, test_extract},
{ "test_zeroblob", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, test_zeroblob},
+ { "test_getsubtype", 1, SQLITE_UTF8, test_getsubtype},
+ { "test_setsubtype", 2, SQLITE_UTF8, test_setsubtype},
};
int i;
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 4a90ed648..7884d955b 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -175,6 +175,7 @@ struct Mem {
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+ u8 eSubtype; /* Subtype for this value */
int n; /* Number of characters in string value, excluding '\0' */
char *z; /* String or BLOB value */
/* ShallowCopy only needs to copy the information above */
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index faf97634c..06b14e127 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -187,6 +187,9 @@ int sqlite3_value_int(sqlite3_value *pVal){
sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
+unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
+ return ((Mem*)pVal)->eSubtype;
+}
const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
@@ -365,6 +368,10 @@ void sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
+void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ pCtx->pOut->eSubtype = eSubtype & 0xff;
+}
void sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
diff --git a/test/json101.test b/test/json101.test
index 1a84a5fc5..9543ccfd2 100644
--- a/test/json101.test
+++ b/test/json101.test
@@ -16,9 +16,21 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
load_static_extension db json
-do_execsql_test json1-1.1 {
+do_execsql_test json1-1.1.00 {
SELECT json_array(1,2.5,null,'hello');
} {[1,2.5,null,"hello"]}
+do_execsql_test json1-1.1.01 {
+ SELECT json_array(1,'{"abc":2.5,"def":null,"ghi":hello}',99);
+ -- the second term goes in as a string:
+} {[1,"{\\"abc\\":2.5,\\"def\\":null,\\"ghi\\":hello}",99]}
+do_execsql_test json1-1.1.02 {
+ SELECT json_array(1,json('{"abc":2.5,"def":null,"ghi":"hello"}'),99);
+ -- the second term goes in as JSON
+} {[1,{"abc":2.5,"def":null,"ghi":"hello"},99]}
+do_execsql_test json1-1.1.03 {
+ SELECT json_array(1,json_object('abc',2.5,'def',null,'ghi','hello'),99);
+ -- the second term goes in as JSON
+} {[1,{"abc":2.5,"def":null,"ghi":"hello"},99]}
do_execsql_test json1-1.2 {
SELECT hex(json_array('String "\ Test'));
} {5B22537472696E67205C225C5C2054657374225D}
@@ -54,13 +66,13 @@ do_execsql_test json1-3.1 {
SELECT json_replace('{"a":1,"b":2}','$.a','[3,4,5]');
} {{{"a":"[3,4,5]","b":2}}}
do_execsql_test json1-3.2 {
- SELECT json_replace('{"a":1,"b":2}','$$.a','[3,4,5]');
+ SELECT json_replace('{"a":1,"b":2}','$.a',json('[3,4,5]'));
} {{{"a":[3,4,5],"b":2}}}
do_execsql_test json1-3.3 {
SELECT json_type(json_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b');
} {text}
do_execsql_test json1-3.4 {
- SELECT json_type(json_set('{"a":1,"b":2}','$$.b','{"x":3,"y":4}'),'$.b');
+ SELECT json_type(json_set('{"a":1,"b":2}','$.b',json('{"x":3,"y":4}')),'$.b');
} {object}
# Per rfc7159, any JSON value is allowed at the top level, and whitespace
diff --git a/test/subtype1.test b/test/subtype1.test
new file mode 100644
index 000000000..101961102
--- /dev/null
+++ b/test/subtype1.test
@@ -0,0 +1,31 @@
+# 2015-09-10
+#
+# 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 file implements tests for sqlite3_value_subtype() and
+# sqlite3_result_subtype() interfaces.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_execsql_test subtype1-100 {
+ SELECT test_getsubtype('hello');
+} {0}
+do_execsql_test subtype1-110 {
+ SELECT test_getsubtype(test_setsubtype('hello',123));
+} {123}
+do_execsql_test subtype1-120 {
+ SELECT typeof(test_setsubtype('hello',123));
+} {text}
+do_execsql_test subtype1-130 {
+ SELECT test_setsubtype('hello',123);
+} {hello}
+
+finish_test