Merge the JSON interface into the core. Add -> and ->> operators for JSON

that are compatible with by MySQL and PG.

FossilOrigin-Name: 4cbb3e3efeb40cc41df15e96c7a0c9d6a8c12ca9f2c139ff1b31ea5416735d34
This commit is contained in:
drh
2022-01-11 23:28:12 +00:00
20 changed files with 505 additions and 322 deletions
+5 -5
View File
@@ -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
+5 -5
View File
@@ -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
Vendored
+21 -21
View File
@@ -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.
+13 -12
View File
@@ -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.
+144
View File
@@ -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.
<table border=1 cellpadding=5 cellspacing=0>
<tr><th>JSON<th>PATH<th>-&gt; operator<br>(all)<th>-&gt;&gt; operator<br>(MySQL/PG)
<th>-&gt;&gt; operator<br>(SQLite)<th>json_extract()<br>(SQLite)
<tr><td> **'{"a":123}'** <td>'$.a'<td> **'123'** <td> '123' <td> 123 <td> 123
<tr><td> **'{"a":4.5}'** <td>'$.a'<td> **'4.5'** <td> '4.5' <td> 4.5 <td> 4.5
<tr><td> **'{"a":"xyz"}'** <td>'$.a'<td> **'"xyz"'** <td> 'xyz' <td> 'xyz' <td> 'xyz'
<tr><td> **'{"a":null}'** <td>'$.a'<td> **'null'** <td> NULL <td> NULL <td> NULL
<tr><td> **'{"a":[6,7,8]}'** <td>'$.a'<td> **'[6,7,8]'** <td> '[6,7,8]' <td> '[6,7,8]' <td> **'[6,7,8]'**
<tr><td> **'{"a":{"x":9}}'** <td>'$.a'<td> **'{"x":9}'** <td> '{"x":9}' <td> '{"x":9}' <td> **'{"x":9}'**
<tr><td> **'{"b":999}'** <td>'$.a'<td> NULL <td> NULL <td> NULL <td> NULL
</table>
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.
<table border=1 cellpadding=5 cellspacing=0>
<tr><th>SQL expression <th>Works in MySQL?<th>Works in PG?<th>Works in SQLite
<tr><td>value1-&gt;'$.a' <td> yes <td> no <td> yes
<tr><td>value1-&gt;'a' <td> no <td> yes <td> yes
<tr><td>value2-&gt;'$[2]' <td> yes <td> no <td> yes
<tr><td>value2-&gt;2 <td> no <td> yes <td> yes
</table>
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.
+4 -7
View File
@@ -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];
}
+2 -5
View File
@@ -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
+24 -22
View File
@@ -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.
+1 -1
View File
@@ -1 +1 @@
71272caff5874137ad0b1ddfc22ced4bb66e6c97f7868fdae0347a186f589b38
4cbb3e3efeb40cc41df15e96c7a0c9d6a8c12ca9f2c139ff1b31ea5416735d34
-1
View File
@@ -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 ){
+3 -3
View File
@@ -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
+13
View File
@@ -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 */
+176 -231
View File
@@ -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 <assert.h>, in order to disable asserts().
*/
#if !defined(SQLITE_AMALGAMATION) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
/* 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 <ctype.h> /* 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; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
pNode = jsonLookup(p, zPath, 0, ctx);
if( p->nErr ) 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; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
pNode = jsonLookup(p, zPath, 0, ctx);
if( p->nErr ) break;
jsonAppendSeparator(&jx);
if( pNode ){
jsonRenderNode(pNode, &jx, 0);
}else{
jsonAppendRaw(&jx, "null", 4);
}
}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; i<pIdxInfo->nConstraint; 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<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,
(void*)&aFunc[i].flag,
aFunc[i].xFunc, 0, 0);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
SQLITE_SUBTYPE | enc, 0,
aAgg[i].xStep, aAgg[i].xFinal,
aAgg[i].xValue, jsonGroupInverse, 0);
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
int i;
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
}
#endif
return rc;
}
#ifndef SQLITE_CORE
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_json_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
return sqlite3Json1Init(db);
}
#endif
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */
+2 -5
View File
@@ -50,9 +50,6 @@ int sqlite3Fts2Init(sqlite3*);
#ifdef SQLITE_ENABLE_FTS5
int sqlite3Fts5Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_JSON1
int sqlite3Json1Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
int sqlite3StmtVtabInit(sqlite3*);
#endif
@@ -87,8 +84,8 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
sqlite3DbstatRegister,
#endif
sqlite3TestExtInit,
#ifdef SQLITE_ENABLE_JSON1
sqlite3Json1Init,
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
sqlite3JsonTableFunctions,
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
sqlite3StmtVtabInit,
+8 -2
View File
@@ -236,7 +236,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
//
%token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST.
%token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL.
%token OR AND NOT MATCH LIKE_KW BETWEEN IS IN ISNULL NOTNULL NE EQ.
%token OR AND NOT IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ.
%token GT LE LT GE ESCAPE.
// The following directive causes tokens ABORT, AFTER, ASC, etc. to
@@ -286,7 +286,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);}
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%left CONCAT PTR.
%left COLLATE.
%right BITNOT.
%nonassoc ON.
@@ -1235,6 +1235,12 @@ expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] {
/*A-overwrites-B*/
}
expr(A) ::= expr(B) PTR(C) expr(D). {
ExprList *pList = sqlite3ExprListAppend(pParse, 0, B);
pList = sqlite3ExprListAppend(pParse, pList, D);
A = sqlite3ExprFunction(pParse, pList, &C, 0);
}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
+9 -1
View File
@@ -1938,7 +1938,7 @@ struct FuncDestructor {
** are interpreted in the same way as the first 4 parameters to
** FUNCTION().
**
** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters
** are interpreted in the same way as the first 4 parameters to
@@ -1965,6 +1965,10 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
#define JFUNCTION(zName, nArg, iArg, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\
SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -4689,7 +4693,11 @@ FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
void sqlite3RegisterBuiltinFunctions(void);
void sqlite3RegisterDateTimeFunctions(void);
void sqlite3RegisterJsonFunctions(void);
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
int sqlite3JsonTableFunctions(sqlite3*);
#endif
int sqlite3SafetyCheckOk(sqlite3*);
int sqlite3SafetyCheckSickOrOk(sqlite3*);
void sqlite3ChangeCookie(Parse*, int);
+3
View File
@@ -290,6 +290,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
return i;
}else if( z[1]=='>' ){
*tokenType = TK_PTR;
return 2 + (z[2]=='>');
}
*tokenType = TK_MINUS;
return 1;
+15
View File
@@ -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
+56
View File
@@ -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
+1 -1
View File
@@ -429,7 +429,7 @@ foreach file {
fts3_unicode.c
fts3_unicode2.c
json1.c
json.c
rtree.c
icu.c
fts3_icu.c