$(TOP)/ext/fts5/fts5_tcl.c \
$(TOP)/ext/fts5/fts5_test_mi.c \
$(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/json.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)\ext\fts5\fts5_tcl.c \
$(TOP)\ext\fts5\fts5_test_mi.c \
$(TOP)\ext\misc\ieee754.c \
+ $(TOP)\ext\misc\json.c \
$(TOP)\ext\misc\nextchar.c \
$(TOP)\ext\misc\percentile.c \
$(TOP)\ext\misc\regexp.c \
--- /dev/null
+/*
+** 2015-08-12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements JSON functions. The interface is
+** modeled after MySQL JSON functions:
+**
+** https://dev.mysql.com/doc/refman/5.7/en/json.html
+**
+** JSON is pure text. JSONB is a binary encoding that is smaller and easier
+** to parse but which holds the equivalent information. Conversions between
+** JSON and JSONB are lossless.
+**
+** Most of the functions here will accept either JSON or JSONB input. The
+** 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.
+*/
+#include "sqlite3ext.h"
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/* Unsigned integer types */
+typedef sqlite3_uint64 u64;
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+/* An instance of this object represents a JSON string under construction.
+*/
+typedef struct Json Json;
+struct Json {
+ sqlite3_context *pCtx; /* Function context - put error messages here */
+ char *zBuf; /* Append JSON text here */
+ u64 nAlloc; /* Bytes of storage available in zBuf[] */
+ u64 nUsed; /* Bytes of zBuf[] currently used */
+ u8 bStatic; /* True if zBuf is static space */
+ u8 mallocFailed; /* True if an OOM has been encountered */
+ char zSpace[100]; /* Initial static space */
+};
+
+/* Set the Json object to an empty string
+*/
+static void jsonZero(Json *p){
+ p->zBuf = p->zSpace;
+ p->nAlloc = sizeof(p->zSpace);
+ p->nUsed = 0;
+ p->bStatic = 1;
+}
+
+/* Initialize the Json object
+*/
+static void jsonInit(Json *p, sqlite3_context *pCtx){
+ p->pCtx = pCtx;
+ p->mallocFailed = 0;
+ jsonZero(p);
+}
+
+
+/* Free all allocated memory and reset the Json object back to its
+** initial state.
+*/
+static void jsonReset(Json *p){
+ if( !p->bStatic ) sqlite3_free(p->zBuf);
+ jsonZero(p);
+}
+
+
+/* Report an out-of-memory (OOM) condition
+*/
+static void jsonOom(Json *p){
+ p->mallocFailed = 1;
+ sqlite3_result_error_nomem(p->pCtx);
+ jsonReset(p);
+}
+
+/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
+** Return zero on success. Return non-zero on an OOM error
+*/
+static int jsonGrow(Json *p, u32 N){
+ u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+100;
+ char *zNew;
+ if( p->bStatic ){
+ if( p->mallocFailed ) return SQLITE_NOMEM;
+ zNew = sqlite3_malloc64(nTotal);
+ if( zNew==0 ){
+ jsonOom(p);
+ return SQLITE_NOMEM;
+ }
+ memcpy(zNew, p->zBuf, 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;
+}
+
+/* Append N bytes from zIn onto the end of the Json string.
+*/
+static void jsonAppendRaw(Json *p, const char *zIn, u32 N){
+ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+}
+
+/* Append the N-byte string in zIn to the end of the Json string
+** under construction. Enclose the string in "..." and escape
+** any double-quotes or backslash characters contained within the
+** string.
+*/
+static void jsonAppendString(Json *p, const char *zIn, u32 N){
+ u32 i;
+ 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];
+ if( c=='"' || c=='\\' ){
+ if( (p->nUsed+N+1-i > p->nAlloc) && jsonGrow(p,N+1-i)!=0 ) return;
+ p->zBuf[p->nUsed++] = '\\';
+ }
+ p->zBuf[p->nUsed++] = c;
+ }
+ p->zBuf[p->nUsed++] = '"';
+}
+
+/* Make pJson the result of the SQL function.
+*/
+static void jsonResult(Json *p){
+ if( p->mallocFailed==0 ){
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
+ SQLITE_UTF8);
+ 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
+** is a BLOB, throw an error.
+*/
+static void jsonArrayFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ Json jx;
+ char cSep = '[';
+
+ jsonInit(&jx, context);
+ for(i=0; i<argc; i++){
+ jsonAppendRaw(&jx, &cSep, 1);
+ cSep = ',';
+ switch( sqlite3_value_type(argv[i]) ){
+ case SQLITE_NULL: {
+ jsonAppendRaw(&jx, "null", 4);
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ const char *z = (const char*)sqlite3_value_text(argv[i]);
+ u32 n = (u32)sqlite3_value_bytes(argv[i]);
+ jsonAppendRaw(&jx, z, n);
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(argv[i]);
+ u32 n = (u32)sqlite3_value_bytes(argv[i]);
+ jsonAppendString(&jx, z, n);
+ break;
+ }
+ default: {
+ jsonZero(&jx);
+ sqlite3_result_error(context, "JSON cannot hold BLOB values", -1);
+ return;
+ }
+ }
+ }
+ jsonAppendRaw(&jx, "]", 1);
+ jsonResult(&jx);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_json_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ int i;
+ static const struct {
+ const char *zName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "json_array", -1, jsonArrayFunc },
+ };
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
+ SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+ aFunc[i].xFunc, 0, 0);
+ }
+ return rc;
+}
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/fuzzer.c \
$(TOP)/ext/misc/ieee754.c \
+ $(TOP)/ext/misc/json.c \
$(TOP)/ext/misc/nextchar.c \
$(TOP)/ext/misc/percentile.c \
$(TOP)/ext/misc/regexp.c \
-C Add\sthe\sxPhraseFirst()\sand\sxPhraseNext()\sfts5\sAPIs,\sfor\sfaster\siteration\sthrough\sa\ssingle\sphrases\sposition\slist.\sAlso\soptimize\sxInst()\sand\sxInstCount()\sa\sbit.
-D 2015-08-12T12:11:28.744
+C Begin\sadding\san\sextension\sthat\sprovides\sJSON\sSQL\sfunctions.
+D 2015-08-12T16:49:40.032
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380
+F Makefile.in 7669f34c487f5b328de6b508f374ee1e56558bb0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc 5f7861c62c41fe8e3205ef14b90ebed28fa21f1b
+F Makefile.msc 0e9dbc907fbd3e08444b5dd4c03e1919442575b8
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
F VERSION ccfc4d1576dbfdeece0a4372a2e6a2e37d3e7975
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 4c84635c71c26cfa7c2e5848cf49fe2d2cfcd767
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
+F ext/misc/json.c 172375d024d799aa6506b8a329128ee0b67e1a94
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 73167b34b0e67c0be32c1da2d988a376851c9ab1
+F main.mk d79682036d2dbb4197b09bc5c6a448fd35e7fc9a
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
F src/tclsqlite.c d9439b6a910985b7fff43ba6756bcef00de22649
-F src/test1.c d339ae9b9baf9221c657c9628c9061d88bd831f6
+F src/test1.c 0fcf7ae97001ced91bfbfaf738e9689779d9bf61
F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d
F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
+F test/json1.test f09587c250426291faff60cacc5aae759216dbd7
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 61cb2fc6c12810863c965c74e90bc502e20cf810
-R d3b6dadb6d0d16c8d1ad296c14b96300
-U dan
-Z 2a4c5177ad3c19913de9e61965a0ba07
+P f7682435278419829a46bb4cc9b5625d46549e22
+R 400e916c0bc56219e72f7a73e2b83997
+T *branch * json
+T *sym-json *
+T -sym-trunk *
+U drh
+Z 44e10dc14fd52cdaf44120cd6aeb4786
-f7682435278419829a46bb4cc9b5625d46549e22
\ No newline at end of file
+dde8afdd8dba1d92560326dca7c1cdfedbe5e070
\ No newline at end of file
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
+ extern int sqlite3_json_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
{ "fileio", sqlite3_fileio_init },
{ "fuzzer", sqlite3_fuzzer_init },
{ "ieee754", sqlite3_ieee_init },
+ { "json", sqlite3_json_init },
{ "nextchar", sqlite3_nextchar_init },
{ "percentile", sqlite3_percentile_init },
{ "regexp", sqlite3_regexp_init },
--- /dev/null
+# 2015-08-12
+#
+# 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 JSON SQL functions extension to the
+# SQLite library.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+load_static_extension db json
+do_execsql_test json1-1.1 {
+ SELECT json_array(1,2.5,null,'hello');
+} {[1,2.5,null,"hello"]}
+do_execsql_test json1-1.2 {
+ SELECT hex(json_array('String "\ Test'));
+} {5B22537472696E67205C225C5C2054657374225D}
+do_catchsql_test json1-1.3 {
+ SELECT json_array(1,2,x'abcd',3);
+} {1 {JSON cannot hold BLOB values}}
+do_execsql_test json1-1.4 {
+ SELECT json_array(-9223372036854775808,9223372036854775807,0,1,-1,
+ 0.0, 1.0, -1.0, -1e99, +2e100,
+ 'one','two','three',
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, NULL, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
+ 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
+ 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
+ 99);
+} {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]}
+
+finish_test