diff --git a/Makefile.in b/Makefile.in
index b3ea4628b3..9d37f883e9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -180,7 +180,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
- icu.lo insert.lo json1.lo legacy.lo loadext.lo \
+ icu.lo insert.lo json.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memdb.lo memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -234,6 +234,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/json.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -366,7 +367,6 @@ SRC += \
$(TOP)/ext/rbu/sqlite3rbu.h \
$(TOP)/ext/rbu/sqlite3rbu.c
SRC += \
- $(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/stmt.c
# Generated source code files
@@ -873,6 +873,9 @@ hash.lo: $(TOP)/src/hash.c $(HDR)
insert.lo: $(TOP)/src/insert.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c
+json.lo: $(TOP)/src/json.c
+ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/json.c
+
legacy.lo: $(TOP)/src/legacy.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/legacy.c
@@ -1176,9 +1179,6 @@ userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
-json1.lo: $(TOP)/ext/misc/json1.c
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
-
stmt.lo: $(TOP)/ext/misc/stmt.c
$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
diff --git a/Makefile.msc b/Makefile.msc
index 42f4648875..ef78eae62f 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -1248,7 +1248,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
fts5.lo \
func.lo global.lo hash.lo \
- icu.lo insert.lo json1.lo legacy.lo loadext.lo \
+ icu.lo insert.lo json.lo legacy.lo loadext.lo \
main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
memdb.lo memjournal.lo \
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
@@ -1315,6 +1315,7 @@ SRC00 = \
$(TOP)\src\global.c \
$(TOP)\src\hash.c \
$(TOP)\src\insert.c \
+ $(TOP)\src\json.c \
$(TOP)\src\legacy.c \
$(TOP)\src\loadext.c \
$(TOP)\src\main.c \
@@ -1445,7 +1446,6 @@ SRC07 = \
$(TOP)\ext\rtree\rtree.c \
$(TOP)\ext\session\sqlite3session.c \
$(TOP)\ext\rbu\sqlite3rbu.c \
- $(TOP)\ext\misc\json1.c \
$(TOP)\ext\misc\stmt.c
# Extension header files, part 1.
@@ -1990,6 +1990,9 @@ hash.lo: $(TOP)\src\hash.c $(HDR)
insert.lo: $(TOP)\src\insert.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c
+json.lo: $(TOP)\src\json.c $(HDR)
+ $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\json.c
+
legacy.lo: $(TOP)\src\legacy.c $(HDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\legacy.c
@@ -2298,9 +2301,6 @@ fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR)
fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c
-json1.lo: $(TOP)\ext\misc\json1.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\json1.c
-
stmt.lo: $(TOP)\ext\misc\stmt.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\stmt.c
diff --git a/configure b/configure
index 74dddfe76e..abb182d5eb 100755
--- a/configure
+++ b/configure
@@ -905,13 +905,13 @@ enable_debug
enable_amalgamation
enable_load_extension
enable_math
+enable_json
enable_all
enable_memsys5
enable_memsys3
enable_fts3
enable_fts4
enable_fts5
-enable_json1
enable_update_limit
enable_geopoly
enable_rtree
@@ -1560,13 +1560,13 @@ Optional Features:
--disable-load-extension
Disable loading of external extensions
--disable-math Disable math functions
- --enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
+ --disable-json Disable JSON functions
+ --enable-all Enable FTS4, FTS5, Geopoly, RTree, Sessions
--enable-memsys5 Enable MEMSYS5
--enable-memsys3 Enable MEMSYS3
--enable-fts3 Enable the FTS3 extension
--enable-fts4 Enable the FTS4 extension
--enable-fts5 Enable the FTS5 extension
- --enable-json1 Enable the JSON1 extension
--enable-update-limit Enable the UPDATE/DELETE LIMIT clause
--enable-geopoly Enable the GEOPOLY extension
--enable-rtree Enable the RTREE extension
@@ -11497,6 +11497,24 @@ fi
fi
+##########
+# Do we want to support JSON functions
+#
+# Check whether --enable-json was given.
+if test "${enable_json+set}" = set; then :
+ enableval=$enable_json;
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON functions" >&5
+$as_echo_n "checking whether to support JSON functions... " >&6; }
+if test "$enable_json" = "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
########
# The --enable-all argument is short-hand to enable
@@ -11701,24 +11719,6 @@ else
$as_echo "no" >&6; }
fi
-#########
-# See whether we should enable JSON1
-# Check whether --enable-json1 was given.
-if test "${enable_json1+set}" = set; then :
- enableval=$enable_json1;
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support JSON" >&5
-$as_echo_n "checking whether to support JSON... " >&6; }
-if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
#########
# See whether we should enable the LIMIT clause on UPDATE and DELETE
# statements.
diff --git a/configure.ac b/configure.ac
index 32fe0d229a..cc805a00d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -605,12 +605,24 @@ else
AC_SEARCH_LIBS(ceil, m)
fi
+##########
+# Do we want to support JSON functions
+#
+AC_ARG_ENABLE(json,
+AC_HELP_STRING([--disable-json],[Disable JSON functions]))
+AC_MSG_CHECKING([whether to support JSON functions])
+if test "$enable_json" = "no"; then
+ AC_MSG_RESULT([no])
+ OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
+else
+ AC_MSG_RESULT([yes])
+fi
########
# The --enable-all argument is short-hand to enable
# multiple extensions.
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
- [Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
+ [Enable FTS4, FTS5, Geopoly, RTree, Sessions]))
##########
# Do we want to support memsys3 and/or memsys5
@@ -666,17 +678,6 @@ else
AC_MSG_RESULT([no])
fi
-#########
-# See whether we should enable JSON1
-AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
-AC_MSG_CHECKING([whether to support JSON])
-if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
#########
# See whether we should enable the LIMIT clause on UPDATE and DELETE
# statements.
diff --git a/doc/json-enhancements.md b/doc/json-enhancements.md
new file mode 100644
index 0000000000..bc03e8978c
--- /dev/null
+++ b/doc/json-enhancements.md
@@ -0,0 +1,144 @@
+# JSON Functions Enhancements (2022)
+
+This document summaries enhancements to the SQLite JSON support added in
+early 2022.
+
+## 1.0 Change summary:
+
+ 1. New **->** and **->>** operators that work like MySQL and PostgreSQL (PG).
+ 2. JSON functions are built-in rather than being an extension. They
+ are included by default, but can be omitted using the
+ -DSQLITE_OMIT_JSON compile-time option.
+
+
+## 2.0 New operators **->** and **->>**
+
+The SQLite language adds two new binary operators **->** and **->>**.
+Both operators are similar to json_extract(). The left operand is
+JSON and the right operand is a JSON path expression (possibly abbreviated
+for compatibility with PG - see below). So they are similar to a
+two-argument call to json_extract().
+
+The difference between -> and ->> (and json_extract()) is as follows:
+
+ * The -> operator always returns JSON.
+
+ * The ->> operator converts the answer into a primitive SQL datatype
+ such as TEXT, INTEGER, REAL, or NULL. If a JSON object or array
+ is selected, that object or array is rendered as text. If a JSON
+ value is selected, that value is converted into its corresponding
+ SQL type
+
+ * The json_extract() interface returns JSON when a JSON object or
+ array is selected, or a primitive SQL datatype when a JSON value
+ is selected. This is different from MySQL, in which json_extract()
+ always returns JSON, but the difference is retained because it has
+ worked that way for 6 years and changing it now would likely break
+ a lot of legacy code.
+
+In MySQL and PG, the ->> operator always returns TEXT (or NULL) and never
+INTEGER or REAL. This is due to limitations in the type handling capabilities
+of those systems. In MySQL and PG, the result type a function or operator
+may only depend on the type of its arguments, never the value of its arguments.
+But the underlying JSON type depends on the value of the JSON path
+expression, not the type of the JSON path expression (which is always TEXT).
+Hence, the result type of ->> in MySQL and PG is unable to vary according
+to the type of the JSON value being extracted.
+
+The type system in SQLite is more general. Functions in SQLite are able
+to return different datatypes depending on the value of their arguments.
+So the ->> operator in SQLite is able to return TEXT, INTEGER, REAL, or NULL
+depending on the JSON type of the value being extracted. This means that
+the behavior of the ->> is slightly different in SQLite versus MySQL and PG
+in that it will sometimes return INTEGER and REAL values, depending on its
+inputs. It is possible to implement the ->> operator in SQLite so that it
+always operates exactly like MySQL and PG and always returns TEXT or NULL,
+but I have been unable to think of any situations where returning the
+actual JSON value this would cause problems, so I'm including the enhanced
+functionality in SQLite.
+
+The table below attempts to summarize the differences between the
+-> and ->> operators and the json_extract() function, for SQLite, MySQL,
+and PG. JSON values are shown using their SQL text representation but
+in a bold font.
+
+
+
+| JSON | PATH | -> operator (all) | ->> operator (MySQL/PG)
+ | ->> operator (SQLite) | json_extract() (SQLite)
+ |
|---|
| **'{"a":123}'** | '$.a' | **'123'** | '123' | 123 | 123
+ |
| **'{"a":4.5}'** | '$.a' | **'4.5'** | '4.5' | 4.5 | 4.5
+ |
| **'{"a":"xyz"}'** | '$.a' | **'"xyz"'** | 'xyz' | 'xyz' | 'xyz'
+ |
| **'{"a":null}'** | '$.a' | **'null'** | NULL | NULL | NULL
+ |
| **'{"a":[6,7,8]}'** | '$.a' | **'[6,7,8]'** | '[6,7,8]' | '[6,7,8]' | **'[6,7,8]'**
+ |
| **'{"a":{"x":9}}'** | '$.a' | **'{"x":9}'** | '{"x":9}' | '{"x":9}' | **'{"x":9}'**
+ |
| **'{"b":999}'** | '$.a' | NULL | NULL | NULL | NULL
+ |
+
+Important points about the table above:
+
+ * The -> operator always returns either JSON or NULL.
+
+ * The ->> operator never returns JSON. It always returns TEXT or NULL, or in the
+ case of SQLite, INTEGER or REAL.
+
+ * The MySQL json_extract() function works exactly the same
+ as the MySQL -> operator.
+
+ * The SQLite json_extract() operator works like -> for JSON objects and
+ arrays, and like ->> for JSON values.
+
+ * The -> operator works the same for all systems.
+
+ * The only difference in ->> between SQLite and other systems is that
+ when the JSON value is numeric, SQLite returns a numeric SQL value,
+ whereas the other systems return a text representation of the numeric
+ value.
+
+### 2.1 Abbreviated JSON path expressions for PG compatibility
+
+The table above always shows the full JSON path expression: '$.a'. But
+PG does not accept this syntax. PG only allows a single JSON object label
+name or a single integer array index. In order to provide compatibility
+with PG, The -> and ->> operators in SQLite are extended to also support
+a JSON object label or an integer array index for the right-hand side
+operand, in addition to a full JSON path expression.
+
+Thus, a -> or ->> operator that works on MySQL will work in
+SQLite. And a -> or ->> operator that works in PG will work in SQLite.
+But because SQLite supports the union of the disjoint capabilities of
+MySQL and PG, there will always be -> and ->> operators that work in
+SQLite that do not work in one of MySQL and PG. This is an unavoidable
+consequence of the different syntax for -> and ->> in MySQL and PG.
+
+In the following table, assume that "value1" is a JSON object and
+"value2" is a JSON array.
+
+
+| SQL expression | Works in MySQL? | Works in PG? | Works in SQLite
+ |
|---|
| value1->'$.a' | yes | no | yes
+ |
| value1->'a' | no | yes | yes
+ |
| value2->'$[2]' | yes | no | yes
+ |
| value2->2 | no | yes | yes
+ |
+
+The abbreviated JSON path expressions only work for the -> and ->> operators
+in SQLite. The json_extract() function, and all other built-in SQLite
+JSON functions, continue to require complete JSON path expressions for their
+PATH arguments.
+
+## 3.0 JSON moved into the core
+
+The JSON interface is now moved into the SQLite core.
+
+When originally written in 2015, the JSON functions were an extension
+that could be optionally included at compile-time, or loaded at run-time.
+The implementation was in a source file named ext/misc/json1.c in the
+source tree. JSON functions were only compiled in if the
+-DSQLITE_ENABLE_JSON1 compile-time option was used.
+
+After these enhancements, the JSON functions are now built-ins.
+The source file that implements the JSON functions is moved to src/json.c.
+No special compile-time options are needed to load JSON into the build.
+Instead, there is a new -DSQLITE_OMIT_JSON compile-time option to leave
+them out.
diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 98ea718f5a..68cde87344 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -26,11 +26,7 @@
# define GEODEBUG(X)
#endif
-#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
+/* Character class routines */
#ifdef sqlite3Isdigit
/* Use the SQLite core versions if this routine is part of the
** SQLite amalgamation */
@@ -45,6 +41,7 @@
# define safe_isxdigit(x) isxdigit((unsigned char)(x))
#endif
+#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
/*
** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function.
@@ -67,7 +64,7 @@ static const char geopolyIsSpace[] = {
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 safe_isspace(x) (geopolyIsSpace[(unsigned char)x])
+#define fast_isspace(x) (geopolyIsSpace[(unsigned char)x])
#endif /* JSON NULL - back to original code */
/* Compiler and version */
@@ -156,7 +153,7 @@ static void geopolySwab32(unsigned char *a){
/* Skip whitespace. Return the next non-whitespace character. */
static char geopolySkipSpace(GeoParse *p){
- while( safe_isspace(p->z[0]) ) p->z++;
+ while( fast_isspace(p->z[0]) ) p->z++;
return p->z[0];
}
diff --git a/main.mk b/main.mk
index a3a4f33bd3..e09505aee2 100644
--- a/main.mk
+++ b/main.mk
@@ -64,7 +64,7 @@ LIBOBJ+= vdbe.o parse.o \
fts3_tokenize_vtab.o \
fts3_unicode.o fts3_unicode2.o \
fts3_write.o fts5.o func.o global.o hash.o \
- icu.o insert.o json1.o legacy.o loadext.o \
+ icu.o insert.o json.o legacy.o loadext.o \
main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
memdb.o memjournal.o \
mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
@@ -111,6 +111,7 @@ SRC = \
$(TOP)/src/hash.h \
$(TOP)/src/hwtime.h \
$(TOP)/src/insert.c \
+ $(TOP)/src/json.c \
$(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \
$(TOP)/src/main.c \
@@ -244,7 +245,6 @@ SRC += \
$(TOP)/ext/rbu/sqlite3rbu.c \
$(TOP)/ext/rbu/sqlite3rbu.h
SRC += \
- $(TOP)/ext/misc/json1.c \
$(TOP)/ext/misc/stmt.c
@@ -828,9 +828,6 @@ fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
fts5.o: fts5.c sqlite3ext.h sqlite3.h
$(TCCX) -DSQLITE_CORE -c fts5.c
-json1.o: $(TOP)/ext/misc/json1.c sqlite3ext.h sqlite3.h
- $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c
-
stmt.o: $(TOP)/ext/misc/stmt.c sqlite3ext.h sqlite3.h
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
diff --git a/manifest b/manifest
index a1c90a1f9a..460c6519aa 100644
--- a/manifest
+++ b/manifest
@@ -1,11 +1,11 @@
-C Add\sNEVER()\smacros\sto\stwo\sbranches\sthat\sbecame\sunreachable\sdue\sto\n[e199a851e316bd47].
-D 2022-01-08T21:50:00.551
+C Merge\sthe\sJSON\sinterface\sinto\sthe\score.\s\sAdd\s->\sand\s->>\soperators\sfor\sJSON\nthat\sare\scompatible\swith\sby\sMySQL\sand\sPG.
+D 2022-01-11T23:28:12.800
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
-F Makefile.in 0e91c42a1dd13a569b1fa4f4dfb7d3632f3164a1c05c71341533d67db5b641dd
+F Makefile.in fd537743957bfe87997dc5727783d8eec82098921e15eab984d6711cd46f001b
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
-F Makefile.msc 517f22463b99b56f6c4c81afcf09c7bf3a0289d08f2dadcc0d5322819dbd6017
+F Makefile.msc 22ce0007874c61c8eb51fc22b84f72af175ce2d7431c242253bdffa39c163da4
F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c
F VERSION 392c2f83569705069415a5d98b1c138ec8fe8a56a663a0d94cea019e806537b2
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
@@ -34,10 +34,11 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
-F configure 56f2a6637cdba53788673ccc229c4f95ab3ab6fe67036e0b1291dc615e531a58 x
-F configure.ac c8ba54bac7e73e000acdfef5e394fe21a3876aa09d0f5c07131bf5ac5a525299
+F configure a2877fe63cc821af0df41abe70f1f7c4e97cb7e23a42e0a1402e8a2f55a88aa2 x
+F configure.ac 3ef6eeff4387585bfcab76b0c3f6e15a0618587bb90245dd5d44e4378141bb35
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
+F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
@@ -306,7 +307,6 @@ F ext/misc/fileio.c 4e7f7cd30de8df4820c552f14af3c9ca451c5ffe1f2e7bef34d598a12ebf
F ext/misc/fossildelta.c 1240b2d3e52eab1d50c160c7fe1902a9bd210e052dc209200a750bbf885402d5
F ext/misc/fuzzer.c eae560134f66333e9e1ca4c8ffea75df42056e2ce8456734565dbe1c2a92bf3d
F ext/misc/ieee754.c 91a5594071143a4ab79c638fe9f059af1db09932faf2e704c3e29216a7d4f511
-F ext/misc/json1.c a4ea54d9b228901695a7f51df338dddb29a2a574b870d0c0cb58539cc90e9a31
F ext/misc/memstat.c 3017a0832c645c0f8c773435620d663855f04690172316bd127270d1a7523d4d
F ext/misc/memtrace.c 7c0d115d2ef716ad0ba632c91e05bd119cb16c1aedf3bec9f06196ead2d5537b
F ext/misc/memvfs.c 7dffa8cc89c7f2d73da4bd4ccea1bcbd2bd283e3bb4cea398df7c372a197291b
@@ -394,7 +394,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test b530f141413b587c9eb78ff734de6bb79bc3515c335096108c12c01bddbadcec
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/geopoly.c a7021cb524621573ccda213a35b0339371849dd4acc4909f689786ee1f964b7f
+F ext/rtree/geopoly.c cc3f89c11abcf114fa60d74709ae8b5bc1eae5a261b30bc1bb7085089c03bfab
F ext/rtree/rtree.c d7b4b8b81d8d54376a7f81de5be85ec58b37c11604bcf42984a8418b34158d93
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 35c3bc0def71317b7601ee0d1149e7df2cd8fc4f13ec89a64761ac3f46ca123f
@@ -472,7 +472,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 24547d9000c965553e6f5c875d91935eac250ca19ae6d9afa57fe093e3edd257
+F main.mk 32e8c752386520016933873a23a9c649f1a9cfd5c75c218614e622f0510b8f42
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -495,9 +495,9 @@ F src/btree.c 0e9f84f974e970fb373c15caa1624a281b3c33098cb9dd9021d6801c04eb4fde
F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22
F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7
F src/build.c c72407a27a28982a384cd453a3a6b6992a1ceae8bd8d95e96d7fb9c0d645a32f
-F src/callback.c 106b585da1edd57d75fa579d823a5218e0bf37f191dbf7417eeb4a8a9a267dbc
+F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
-F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1
+F src/ctime.c 638e75c9a02b276c782cb27f59f3abf2ab94a33514107ffd165b2f69d1bc2aaa
F src/date.c ab8e01d928f201f5dee0bc6d54d6702fdcec96dff4d58c387447671f6a46d191
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
@@ -505,16 +505,17 @@ F src/delete.c 19814f621cde10b1771a0dea7fe25d3d7d39975b8d4be4888537d30860e7c08c
F src/expr.c 827179c78d2ca7cc318392811de8151c60eacf7ce804b13e61bb7ef38f954846
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560
-F src/func.c bd0feae5c5b1680773930f07604474329e543f63502cb1e0fb127823c2a817da
+F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776
F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743
+F src/json.c f3bbaf6a4df6f5ada5b71e01666f5cd67642c616cd8be47dbfa5b5768dfa71d4 w ext/misc/json1.c
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d
-F src/main.c aa24539f6c26460543d51027ea14b79cad35e34bc9d4907bc349b52b71066644
+F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960
F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -539,7 +540,7 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 5130bd602719ad9de1436def895da73973ee74382db02036be21238d0aa2ccfd
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
-F src/parse.y 761b5d30a7ea9bd2db3b3571438cfcceb5f7dbf4fcad6881c8de65bdda07135a
+F src/parse.y 04f61db1cdd7036c6d74baad1c342d3e3110cb0765c48fcfd3bdf4e974a1e5bb
F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65
@@ -555,7 +556,7 @@ F src/shell.c.in f5111900d646a07da18e6438d57be20f112397daba6bfc85b117a0da586e55d
F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef
-F src/sqliteInt.h 9782b7b22a9b10e43b7f375dcdfb93cd1ed7797d831122a07d065efacf9af668
+F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -614,7 +615,7 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
-F src/tokenize.c dc5367c6d42336b35d55f96d2f04cd6256e92bc6ecf74ed5d855d24e43343aff
+F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446
F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc
F src/trigger.c 40e7c3dcff57a770d5fa38ba21ed4725572fd2e224c58af61eb980598b60f9c8
F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328
@@ -1045,7 +1046,7 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
-F test/func.test 3a65ddb6c1998f71aa86492501a6be87904197e62bfb5b70b2493552b558abd1
+F test/func.test 0a305e88a4fbdce6be8c6f4863d6dab9ecb2975b95e94734621e2c900779b712
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
@@ -1147,7 +1148,7 @@ F test/jrnlmode.test 9b5bc01dac22223cb60ec2d5f97acf568d73820794386de5634dcadbea9
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test bb71538005f2d9e18620bdd3b76839a93ca0be61903eb8d751a64e78cf99b8fb
-F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
+F test/json102.test 86edc7d283085addff8593b178997e75875530d1385f5926717543d3475e6b01
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
F test/json104.test 2cb7ff2cca2c8214d3e5260eeb9ce45faec0926f68b3e40c1aaa6ca247284144
F test/json105.test 45f7d6a9a54c85f8a9589b68d3e7a1f42d02f2359911a8cdbad1f9988f571173
@@ -1875,7 +1876,7 @@ F tool/mkshellc.tcl df5d249617f9cc94d5c48eb0401673eb3f31f383ecbc54e8a13ca3dd97e8
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
-F tool/mksqlite3c.tcl bf9b40811aba68f73f2a8848fad9b1fb09fd54ab5b77e5227f18eea87ab60d92
+F tool/mksqlite3c.tcl 6f9e05facb51e906a1a7ef9f95274ef2ec91bf88b96732a9aed40647c605f419
F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
@@ -1937,8 +1938,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 68bffc612c467b2419bf5fe85a8ca16b787003e0e8c11f7c051a879f5865b847
-R c94d976a37a2f277f5140b8791189b0b
+P 71272caff5874137ad0b1ddfc22ced4bb66e6c97f7868fdae0347a186f589b38 8da07c8b09ff83436a34e539e4cce8ba9524390017ca14f4af8344a12e351550
+R 4fe2152bcfc77f35d559181df42337b8
+T +closed 8da07c8b09ff83436a34e539e4cce8ba9524390017ca14f4af8344a12e351550
U drh
-Z 7446237fb7eda07b8f82330a10b1e8d5
+Z 9fbdecd5bae6b7208ce6f6c24caebc4c
# Remove this line to create a well-formed Fossil manifest.
diff --git a/manifest.uuid b/manifest.uuid
index 36029f2538..f5ad138bbb 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-71272caff5874137ad0b1ddfc22ced4bb66e6c97f7868fdae0347a186f589b38
\ No newline at end of file
+4cbb3e3efeb40cc41df15e96c7a0c9d6a8c12ca9f2c139ff1b31ea5416735d34
\ No newline at end of file
diff --git a/src/callback.c b/src/callback.c
index 936c374abd..7d8f9dcbce 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -358,7 +358,6 @@ void sqlite3InsertBuiltinFuncs(
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = SQLITE_FUNC_HASH(zName[0], nName);
- assert( zName[0]>='a' && zName[0]<='z' );
assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN );
pOther = sqlite3FunctionSearch(h, zName);
if( pOther ){
diff --git a/src/ctime.c b/src/ctime.c
index de68ea7f57..4377528006 100644
--- a/src/ctime.c
+++ b/src/ctime.c
@@ -179,6 +179,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DISABLE_INTRINSIC
"DISABLE_INTRINSIC",
#endif
+#ifdef SQLITE_DISABLE_JSON
+ "DISABLE_JSON",
+#endif
#ifdef SQLITE_DISABLE_LFS
"DISABLE_LFS",
#endif
@@ -257,9 +260,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE",
#endif
-#ifdef SQLITE_ENABLE_JSON1
- "ENABLE_JSON1",
-#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION",
#endif
diff --git a/src/func.c b/src/func.c
index 166bd6f0e4..81accc9cc3 100644
--- a/src/func.c
+++ b/src/func.c
@@ -97,6 +97,17 @@ static void typeofFunc(
sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
}
+/* subtype(X)
+**
+** Return the subtype of X
+*/
+static void subtypeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3_result_int(context, sqlite3_value_subtype(argv[0]));
+}
/*
** Implementation of the length() function
@@ -2246,6 +2257,7 @@ void sqlite3RegisterBuiltinFunctions(void){
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
+ FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
@@ -2348,6 +2360,7 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
sqlite3WindowFunctions();
sqlite3RegisterDateTimeFunctions();
+ sqlite3RegisterJsonFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
#if 0 /* Enable to print out how the built-in functions are hashed */
diff --git a/ext/misc/json1.c b/src/json.c
similarity index 89%
rename from ext/misc/json1.c
rename to src/json.c
index 787b46982e..dbc3faaef3 100644
--- a/ext/misc/json1.c
+++ b/src/json.c
@@ -10,10 +10,10 @@
**
******************************************************************************
**
-** This SQLite extension implements JSON functions. The interface is
-** modeled after MySQL JSON functions:
+** This SQLite JSON functions.
**
-** https://dev.mysql.com/doc/refman/5.7/en/json.html
+** This file began as an extension in ext/misc/json1.c in 2015. That
+** extension proved so useful that it has now been moved into the core.
**
** For the time being, all JSON is stored as pure text. (We might add
** a JSONB type in the future which stores a binary encoding of JSON in
@@ -21,57 +21,8 @@
** This implementation parses JSON text at 250 MB/s, so it is hard to see
** how JSONB might improve on that.)
*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
-#if !defined(SQLITEINT_H)
-#include "sqlite3ext.h"
-#endif
-SQLITE_EXTENSION_INIT1
-
-/* If compiling this extension separately (why would anybody do that when
-** it is built into the amalgamation?) we must set NDEBUG if SQLITE_DEBUG
-** is not defined *before* including , in order to disable asserts().
-*/
-#if !defined(SQLITE_AMALGAMATION) && !defined(SQLITE_DEBUG)
-# define NDEBUG 1
-#endif
-
-#include
-#include
-#include
-#include
-
-/* 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))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-#ifndef deliberate_fall_through
-# define deliberate_fall_through
-#endif
-
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
-#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_isxdigit(x) sqlite3Isxdigit(x)
-#else
- /* Use the standard library for separate compilation */
-#include /* amalgamator: keep */
-# 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
+#ifndef SQLITE_OMIT_JSON
+#include "sqliteInt.h"
/*
** Growing our own isspace() routine this way is twice as fast as
@@ -96,44 +47,14 @@ static const char jsonIsSpace[] = {
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 safe_isspace(x) (jsonIsSpace[(unsigned char)x])
+#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
-#ifndef SQLITE_AMALGAMATION
- /* Unsigned integer types. These are already defined in the sqliteInt.h,
- ** but the definitions need to be repeated for separate compilation. */
- typedef sqlite3_uint64 u64;
- typedef unsigned int u32;
- typedef unsigned short int u16;
- typedef unsigned char u8;
-# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
-# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
-# endif
-# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
-# define ALWAYS(X) (1)
-# define NEVER(X) (0)
-# elif !defined(NDEBUG)
-# define ALWAYS(X) ((X)?1:(assert(0),0))
-# define NEVER(X) ((X)?(assert(0),1):0)
-# else
-# define ALWAYS(X) (X)
-# define NEVER(X) (X)
-# endif
-# define testcase(X)
-#endif
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
# define VVA(X)
#else
# define VVA(X) X
#endif
-/*
-** Some of the testcase() macros in this file are problematic for gcov
-** in that they generate false-miss errors randomly. This is a gcov problem,
-** not a problem in this case. But to work around it, we disable the
-** problematic test cases for production builds.
-*/
-#define json_testcase(X)
-
/* Objects */
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
@@ -591,10 +512,10 @@ static u8 jsonHexToInt(int h){
*/
static u32 jsonHexToInt4(const char *z){
u32 v;
- assert( safe_isxdigit(z[0]) );
- assert( safe_isxdigit(z[1]) );
- assert( safe_isxdigit(z[2]) );
- assert( safe_isxdigit(z[3]) );
+ 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)
@@ -829,7 +750,7 @@ static int jsonParseAddNode(
*/
static int jsonIs4Hex(const char *z){
int i;
- for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+ for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
return 1;
}
@@ -848,13 +769,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
int x;
JsonNode *pNode;
const char *z = pParse->zJson;
- while( safe_isspace(z[i]) ){ i++; }
+ while( fast_isspace(z[i]) ){ i++; }
if( (c = z[i])=='{' ){
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
for(j=i+1;;j++){
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
if( x<0 ){
@@ -867,14 +788,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( pNode->eType!=JSON_STRING ) return -1;
pNode->jnFlags |= JNODE_LABEL;
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( z[j]!=':' ) return -1;
j++;
x = jsonParseValue(pParse, j);
pParse->iDepth--;
if( x<0 ) return -1;
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
c = z[j];
if( c==',' ) continue;
if( c!='}' ) return -1;
@@ -888,7 +809,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( iThis<0 ) return -1;
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
pParse->iDepth--;
@@ -897,7 +818,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
return -1;
}
j = x;
- while( safe_isspace(z[j]) ){ j++; }
+ while( fast_isspace(z[j]) ){ j++; }
c = z[j];
if( c==',' ) continue;
if( c!=']' ) return -1;
@@ -934,17 +855,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
return j+1;
}else if( c=='n'
&& strncmp(z+i,"null",4)==0
- && !safe_isalnum(z[i+4]) ){
+ && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
return i+4;
}else if( c=='t'
&& strncmp(z+i,"true",4)==0
- && !safe_isalnum(z[i+4]) ){
+ && !sqlite3Isalnum(z[i+4]) ){
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
return i+4;
}else if( c=='f'
&& strncmp(z+i,"false",5)==0
- && !safe_isalnum(z[i+5]) ){
+ && !sqlite3Isalnum(z[i+5]) ){
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
return i+5;
}else if( c=='-' || (c>='0' && c<='9') ){
@@ -1015,7 +936,7 @@ static int jsonParse(
if( pParse->oom ) i = -1;
if( i>0 ){
assert( pParse->iDepth==0 );
- while( safe_isspace(zJson[i]) ) i++;
+ while( fast_isspace(zJson[i]) ) i++;
if( zJson[i] ) i = -1;
}
if( i<=0 ){
@@ -1243,7 +1164,7 @@ static JsonNode *jsonLookupStep(
}else if( zPath[0]=='[' ){
i = 0;
j = 1;
- while( safe_isdigit(zPath[j]) ){
+ while( sqlite3Isdigit(zPath[j]) ){
i = i*10 + zPath[j] - '0';
j++;
}
@@ -1264,13 +1185,13 @@ static JsonNode *jsonLookupStep(
j = 1;
}
j = 2;
- if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
+ if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
unsigned int x = 0;
j = 3;
do{
x = x*10 + zPath[j] - '0';
j++;
- }while( safe_isdigit(zPath[j]) );
+ }while( sqlite3Isdigit(zPath[j]) );
if( x>i ) return 0;
i -= x;
}
@@ -1489,7 +1410,7 @@ static void jsonTest1Func(
int argc,
sqlite3_value **argv
){
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
}
#endif /* SQLITE_DEBUG */
@@ -1510,7 +1431,7 @@ static void jsonQuoteFunc(
sqlite3_value **argv
){
JsonString jx;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
jsonInit(&jx, ctx);
jsonAppendValue(&jx, argv[0]);
@@ -1581,13 +1502,34 @@ static void jsonArrayLengthFunc(
sqlite3_result_int64(ctx, n);
}
+/*
+** Bit values for the flags passed into jsonExtractFunc() or
+** jsonSetFunc() via the user-data value.
+*/
+#define JSON_JSON 0x01 /* Result is always JSON */
+#define JSON_SQL 0x02 /* Result is always SQL */
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+
/*
** json_extract(JSON, PATH, ...)
+** "->"(JSON,PATH)
+** "->>"(JSON,PATH)
**
-** Return the element described by PATH. Return NULL if there is no
-** PATH element. If there are multiple PATHs, then return a JSON array
-** with the result from each path. Throw an error if the JSON or any PATH
-** is malformed.
+** Return the element described by PATH. Return NULL if that PATH element
+** is not found.
+**
+** If JSON_JSON is set or if more that one PATH argument is supplied then
+** always return a JSON representation of the result. If JSON_SQL is set,
+** then always return an SQL representation of the result. If neither flag
+** is present and argc==2, then return JSON for objects and arrays and SQL
+** for all other values.
+**
+** When multiple PATH arguments are supplied, the result is a JSON array
+** containing the result of each PATH.
+**
+** Abbreviated JSON path expressions are allows if JSON_ABPATH, for
+** compatibility with PG.
*/
static void jsonExtractFunc(
sqlite3_context *ctx,
@@ -1597,35 +1539,77 @@ static void jsonExtractFunc(
JsonParse *p; /* The parse */
JsonNode *pNode;
const char *zPath;
+ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
JsonString jx;
- int i;
if( argc<2 ) return;
p = jsonParseCached(ctx, argv, ctx);
if( p==0 ) return;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; inErr ) break;
- if( argc>2 ){
+ if( argc==2 ){
+ /* With a single PATH argument */
+ zPath = (const char*)sqlite3_value_text(argv[1]);
+ if( zPath==0 ) return;
+ if( flags & JSON_ABPATH ){
+ if( zPath[0]!='$' ){
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
+ ** is mostly for compatibility with PostgreSQL, but also for
+ ** convenience.
+ **
+ ** NUMBER ==> $[NUMBER] // PG compatible
+ ** LABEL ==> $.LABEL // PG compatible
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ */
+ 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{
+ /* Two or more PATH arguments results in a JSON array with each
+ ** element of the array being the value selected by one of the PATHs */
+ int i;
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=1; inErr ) break;
jsonAppendSeparator(&jx);
if( pNode ){
jsonRenderNode(pNode, &jx, 0);
}else{
jsonAppendRaw(&jx, "null", 4);
}
- }else if( pNode ){
- jsonReturn(pNode, ctx, 0);
}
+ if( i==argc ){
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+ jsonReset(&jx);
}
- if( argc>2 && i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
- }
- jsonReset(&jx);
}
/* This is the RFC 7396 MergePatch algorithm.
@@ -1721,7 +1705,7 @@ static void jsonPatchFunc(
JsonParse y; /* The patch */
JsonNode *pResult; /* The result of the merge */
- UNUSED_PARAM(argc);
+ 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);
@@ -1842,7 +1826,7 @@ static void jsonReplaceFunc(
if( x.nErr ) goto replace_err;
if( pNode ){
assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- json_testcase( pNode->eU!=0 && pNode->eU!=1 );
+ testcase( pNode->eU!=0 && pNode->eU!=1 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
VVA( pNode->eU = 4 );
pNode->u.iReplace = i + 1;
@@ -1858,6 +1842,7 @@ replace_err:
jsonParseReset(&x);
}
+
/*
** json_set(JSON, PATH, VALUE, ...)
**
@@ -1880,7 +1865,7 @@ static void jsonSetFunc(
const char *zPath;
u32 i;
int bApnd;
- int bIsSet = *(int*)sqlite3_user_data(ctx);
+ int bIsSet = sqlite3_user_data(ctx)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
@@ -1899,7 +1884,7 @@ static void jsonSetFunc(
}else if( x.nErr ){
goto jsonSetDone;
}else if( pNode && (bApnd || bIsSet) ){
- json_testcase( pNode->eU!=0 && pNode->eU!=1 && pNode->eU!=4 );
+ testcase( pNode->eU!=0 && pNode->eU!=1 && pNode->eU!=4 );
assert( pNode->eU!=3 || pNode->eU!=5 );
VVA( pNode->eU = 4 );
pNode->jnFlags |= (u8)JNODE_REPLACE;
@@ -1920,8 +1905,8 @@ jsonSetDone:
** json_type(JSON)
** json_type(JSON, PATH)
**
-** Return the top-level "type" of a JSON string. Throw an error if
-** either the JSON or PATH inputs are not well-formed.
+** Return the top-level "type" of a JSON string. json_type() raises an
+** error if either the JSON or PATH inputs are not well-formed.
*/
static void jsonTypeFunc(
sqlite3_context *ctx,
@@ -1957,7 +1942,7 @@ static void jsonValidFunc(
sqlite3_value **argv
){
JsonParse *p; /* The parse */
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
p = jsonParseCached(ctx, argv, 0);
sqlite3_result_int(ctx, p!=0);
}
@@ -1977,7 +1962,7 @@ static void jsonArrayStep(
sqlite3_value **argv
){
JsonString *pStr;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -2037,8 +2022,8 @@ static void jsonGroupInverse(
char *z;
char c;
JsonString *pStr;
- UNUSED_PARAM(argc);
- UNUSED_PARAM(argv);
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
@@ -2082,7 +2067,7 @@ static void jsonObjectStep(
JsonString *pStr;
const char *z;
u32 n;
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(argc);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
@@ -2173,10 +2158,10 @@ static int jsonEachConnect(
#define JEACH_JSON 8
#define JEACH_ROOT 9
- UNUSED_PARAM(pzErr);
- UNUSED_PARAM(argv);
- UNUSED_PARAM(argc);
- UNUSED_PARAM(pAux);
+ 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)");
@@ -2199,7 +2184,7 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
JsonEachCursor *pCur;
- UNUSED_PARAM(p);
+ UNUSED_PARAMETER(p);
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
@@ -2259,7 +2244,7 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
p->eType = pUp->eType;
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==0 || pUp->eU==3 );
- json_testcase( pUp->eU==3 );
+ testcase( pUp->eU==3 );
VVA( pUp->eU = 3 );
if( iUp==p->i-1 ){
pUp->u.iKey = 0;
@@ -2446,7 +2431,7 @@ static int jsonEachBestIndex(
/* This implementation assumes that JSON and ROOT are the last two
** columns in the table */
assert( JEACH_ROOT == JEACH_JSON+1 );
- UNUSED_PARAM(tab);
+ UNUSED_PARAMETER(tab);
aIdx[0] = aIdx[1] = -1;
pConstraint = pIdxInfo->aConstraint;
for(i=0; inConstraint; i++, pConstraint++){
@@ -2502,8 +2487,8 @@ static int jsonEachFilter(
const char *zRoot = 0;
sqlite3_int64 n;
- UNUSED_PARAM(idxStr);
- UNUSED_PARAM(argc);
+ UNUSED_PARAMETER(idxStr);
+ UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
z = (const char*)sqlite3_value_text(argv[0]);
@@ -2628,103 +2613,63 @@ static sqlite3_module jsonTreeModule = {
0 /* xShadowName */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+#endif /* !defined(SQLITE_OMIT_JSON) */
-/****************************************************************************
-** The following routines are the only publically visible identifiers in this
-** file. Call the following routines in order to register the various SQL
-** functions and the virtual table implemented by this file.
-****************************************************************************/
-
-int sqlite3Json1Init(sqlite3 *db){
- int rc = SQLITE_OK;
- unsigned int i;
- static const struct {
- const char *zName;
- int nArg;
- 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 },
- { "json_extract", -1, 0, jsonExtractFunc },
- { "json_insert", -1, 0, jsonSetFunc },
- { "json_object", -1, 0, jsonObjectFunc },
- { "json_patch", 2, 0, jsonPatchFunc },
- { "json_quote", 1, 0, jsonQuoteFunc },
- { "json_remove", -1, 0, jsonRemoveFunc },
- { "json_replace", -1, 0, jsonReplaceFunc },
- { "json_set", -1, 1, jsonSetFunc },
- { "json_type", 1, 0, jsonTypeFunc },
- { "json_type", 2, 0, jsonTypeFunc },
- { "json_valid", 1, 0, jsonValidFunc },
-
+/*
+** Register JSON functions.
+*/
+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_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
- /* DEBUG and TESTING functions */
- { "json_parse", 1, 0, jsonParseFunc },
- { "json_test1", 1, 0, jsonTest1Func },
+ 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|SQLITE_INNOCUOUS),
+ WAGGREGATE(json_group_object, 2, 0, 0,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
};
+ sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
+#endif
+}
+
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
+/*
+** Register the JSON table-valued functions
+*/
+int sqlite3JsonTableFunctions(sqlite3 *db){
+ int rc = SQLITE_OK;
static const struct {
- const char *zName;
- int nArg;
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
- void (*xFinal)(sqlite3_context*);
- void (*xValue)(sqlite3_context*);
- } aAgg[] = {
- { "json_group_array", 1,
- jsonArrayStep, jsonArrayFinal, jsonArrayValue },
- { "json_group_object", 2,
- jsonObjectStep, jsonObjectFinal, jsonObjectValue },
- };
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- static const struct {
- const char *zName;
- sqlite3_module *pModule;
+ const char *zName;
+ sqlite3_module *pModule;
} aMod[] = {
{ "json_each", &jsonEachModule },
{ "json_tree", &jsonTreeModule },
};
-#endif
- static const int enc =
- SQLITE_UTF8 |
- SQLITE_DETERMINISTIC |
- SQLITE_INNOCUOUS;
- for(i=0; i' ){
+ *tokenType = TK_PTR;
+ return 2 + (z[2]=='>');
}
*tokenType = TK_MINUS;
return 1;
diff --git a/test/func.test b/test/func.test
index ca1027f508..008819baa5 100644
--- a/test/func.test
+++ b/test/func.test
@@ -1507,4 +1507,19 @@ do_execsql_test func-35.200 {
PRAGMA integrity_check;
} {ok}
+# 2021-01-07: The -> and ->> operators.
+#
+proc ptr1 {a b} { return "$a->$b" }
+db func -> ptr1
+proc ptr2 {a b} { return "$a->>$b" }
+db func ->> ptr2
+do_execsql_test func-36.100 {
+ SELECT 123 -> 456
+} {123->456}
+do_execsql_test func-36.110 {
+ SELECT 123 ->> 456
+} {123->>456}
+
+
+
finish_test
diff --git a/test/json102.test b/test/json102.test
index 18a6bbf5cc..9f8f482b85 100644
--- a/test/json102.test
+++ b/test/json102.test
@@ -337,4 +337,60 @@ do_execsql_test json102-1501 {
SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x;
} {31}
+# 2022-01-10 tests for -> and ->> operators
+#
+reset_db
+do_execsql_test json102-1600 {
+ CREATE TABLE t1(id INTEGER PRIMARY KEY, x JSON);
+ INSERT INTO t1(id,x) VALUES
+ (1, '{"a":null}'),
+ (2, '{"a":123}'),
+ (3, '{"a":4.5}'),
+ (4, '{"a":"six"}'),
+ (5, '{"a":[7,8]}'),
+ (6, '{"a":{"b":9}}'),
+ (7, '{"b":999}');
+ SELECT
+ id,
+ x->'a' AS '->',
+ CASE WHEN subtype(x->'a') THEN 'json' ELSE typeof(x->'a') END AS 'type',
+ x->>'a' AS '->>',
+ CASE WHEN subtype(x->>'a') THEN 'json' ELSE typeof(x->>'a') END AS 'type',
+ json_extract(x,'$.a') AS 'json_extract',
+ CASE WHEN subtype(json_extract(x,'$.a'))
+ THEN 'json' ELSE typeof(json_extract(x,'$.a')) END AS 'type'
+ FROM t1 ORDER BY id;
+} [list \
+ 1 null json {} null {} null \
+ 2 123 json 123 integer 123 integer \
+ 3 4.5 json 4.5 real 4.5 real \
+ 4 {"six"} json six text six text \
+ 5 {[7,8]} json {[7,8]} text {[7,8]} json \
+ 6 {{"b":9}} json {{"b":9}} text {{"b":9}} json \
+ 7 {} null {} null {} null
+]
+do_execsql_test json102-1610 {
+ DELETE FROM t1;
+ INSERT INTO t1(x) VALUES('[null,123,4.5,"six",[7,8],{"b":9}]');
+ WITH c(y) AS (VALUES(0),(1),(2),(3),(4),(5),(6))
+ SELECT
+ y,
+ x->y AS '->',
+ CASE WHEN subtype(x->y) THEN 'json' ELSE typeof(x->y) END AS 'type',
+ x->>y AS '->>',
+ CASE WHEN subtype(x->>y) THEN 'json' ELSE typeof(x->>y) END AS 'type',
+ json_extract(x,format('$[%d]',y)) AS 'json_extract',
+ CASE WHEN subtype(json_extract(x,format('$[%d]',y)))
+ THEN 'json' ELSE typeof(json_extract(x,format('$[%d]',y))) END AS 'type'
+ FROM c, t1 ORDER BY y;
+} [list \
+ 0 null json {} null {} null \
+ 1 123 json 123 integer 123 integer \
+ 2 4.5 json 4.5 real 4.5 real \
+ 3 {"six"} json six text six text \
+ 4 {[7,8]} json {[7,8]} text {[7,8]} json \
+ 5 {{"b":9}} json {{"b":9}} text {{"b":9}} json \
+ 6 {} null {} null {} null
+]
+
finish_test
diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl
index 9d59e17b16..1a35fc0ea3 100644
--- a/tool/mksqlite3c.tcl
+++ b/tool/mksqlite3c.tcl
@@ -429,7 +429,7 @@ foreach file {
fts3_unicode.c
fts3_unicode2.c
- json1.c
+ json.c
rtree.c
icu.c
fts3_icu.c