Fossil SCM

Sync with trunk.

florian 2024-09-06 10:56 UTC diff-word-wrap merge
Commit b97f0310f042682afda72fea562fdde58eccd3aa392cd256c2bdf8df566552f0
+2 -2
--- auto.def
+++ auto.def
@@ -745,11 +745,12 @@
745745
define FOSSIL_HAVE_GETPASS 1
746746
msg-result "Found getpass() with unistd.h"
747747
}
748748
749749
# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
750
-if {![cc-check-functions getloadavg]} {
750
+if {![cc-check-functions getloadavg] ||
751
+ ![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
751752
define FOSSIL_OMIT_LOAD_AVERAGE 1
752753
msg-result "Load average support unavailable"
753754
}
754755
755756
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
@@ -764,11 +765,10 @@
764765
if {[opt-bool static]} {
765766
msg-result "FuseFS support disabled due to -static"
766767
} elseif {[cc-check-function-in-lib fuse_mount fuse]} {
767768
define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
768769
define FOSSIL_HAVE_FUSEFS 1
769
- define-append LIBS -lfuse
770770
msg-result "FuseFS support enabled"
771771
}
772772
}
773773
774774
########################################################################
775775
--- auto.def
+++ auto.def
@@ -745,11 +745,12 @@
745 define FOSSIL_HAVE_GETPASS 1
746 msg-result "Found getpass() with unistd.h"
747 }
748
749 # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
750 if {![cc-check-functions getloadavg]} {
 
751 define FOSSIL_OMIT_LOAD_AVERAGE 1
752 msg-result "Load average support unavailable"
753 }
754
755 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
@@ -764,11 +765,10 @@
764 if {[opt-bool static]} {
765 msg-result "FuseFS support disabled due to -static"
766 } elseif {[cc-check-function-in-lib fuse_mount fuse]} {
767 define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
768 define FOSSIL_HAVE_FUSEFS 1
769 define-append LIBS -lfuse
770 msg-result "FuseFS support enabled"
771 }
772 }
773
774 ########################################################################
775
--- auto.def
+++ auto.def
@@ -745,11 +745,12 @@
745 define FOSSIL_HAVE_GETPASS 1
746 msg-result "Found getpass() with unistd.h"
747 }
748
749 # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
750 if {![cc-check-functions getloadavg] ||
751 ![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
752 define FOSSIL_OMIT_LOAD_AVERAGE 1
753 msg-result "Load average support unavailable"
754 }
755
756 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
@@ -764,11 +765,10 @@
765 if {[opt-bool static]} {
766 msg-result "FuseFS support disabled due to -static"
767 } elseif {[cc-check-function-in-lib fuse_mount fuse]} {
768 define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
769 define FOSSIL_HAVE_FUSEFS 1
 
770 msg-result "FuseFS support enabled"
771 }
772 }
773
774 ########################################################################
775
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,6 +1,6 @@
1
-README.autosetup created by autosetup v0.7.1+
1
+README.autosetup created by autosetup v0.7.2
22
33
This is the autosetup directory for a local install of autosetup.
44
It contains autosetup, support files and loadable modules.
55
66
*.tcl files in this directory are optional modules which
77
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,6 +1,6 @@
1 README.autosetup created by autosetup v0.7.1+
2
3 This is the autosetup directory for a local install of autosetup.
4 It contains autosetup, support files and loadable modules.
5
6 *.tcl files in this directory are optional modules which
7
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,6 +1,6 @@
1 README.autosetup created by autosetup v0.7.2
2
3 This is the autosetup directory for a local install of autosetup.
4 It contains autosetup, support files and loadable modules.
5
6 *.tcl files in this directory are optional modules which
7
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -4,11 +4,11 @@
44
# vim:se syntax=tcl:
55
# \
66
dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
77
88
# Note that the version has a trailing + on unreleased versions
9
-set autosetup(version) 0.7.1+
9
+set autosetup(version) 0.7.2
1010
1111
# Can be set to 1 to debug early-init problems
1212
set autosetup(debug) [expr {"--debug" in $argv}]
1313
1414
##################################################################
1515
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -4,11 +4,11 @@
4 # vim:se syntax=tcl:
5 # \
6 dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
7
8 # Note that the version has a trailing + on unreleased versions
9 set autosetup(version) 0.7.1+
10
11 # Can be set to 1 to debug early-init problems
12 set autosetup(debug) [expr {"--debug" in $argv}]
13
14 ##################################################################
15
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -4,11 +4,11 @@
4 # vim:se syntax=tcl:
5 # \
6 dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
7
8 # Note that the version has a trailing + on unreleased versions
9 set autosetup(version) 0.7.2
10
11 # Can be set to 1 to debug early-init problems
12 set autosetup(debug) [expr {"--debug" in $argv}]
13
14 ##################################################################
15
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -7,10 +7,10 @@
77
for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
88
{ $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
99
done
1010
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
1111
for cc in ${CC_FOR_BUILD:-cc} gcc; do
12
- { $cc -o jimsh0 "$d/jimsh0.c"; } 2>/dev/null || continue
12
+ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev/null || continue
1313
./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
1414
done
1515
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
1616
echo false
1717
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -7,10 +7,10 @@
7 for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
8 { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
9 done
10 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
11 for cc in ${CC_FOR_BUILD:-cc} gcc; do
12 { $cc -o jimsh0 "$d/jimsh0.c"; } 2>/dev/null || continue
13 ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
14 done
15 echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
16 echo false
17
--- autosetup/autosetup-find-tclsh
+++ autosetup/autosetup-find-tclsh
@@ -7,10 +7,10 @@
7 for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
8 { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
9 done
10 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
11 for cc in ${CC_FOR_BUILD:-cc} gcc; do
12 { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev/null || continue
13 ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
14 done
15 echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
16 echo false
17
+306 -179
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,10 +1,11 @@
11
/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
22
#define JIM_TCL_COMPAT
33
#define JIM_ANSIC
44
#define JIM_REGEXP
55
#define HAVE_NO_AUTOCONF
6
+#define JIM_TINY
67
#define _JIMAUTOCONF_H
78
#define TCL_LIBRARY "."
89
#define jim_ext_bootstrap
910
#define jim_ext_aio
1011
#define jim_ext_readdir
@@ -60,11 +61,11 @@
6061
#define HAVE_UNISTD_H
6162
#define HAVE_UMASK
6263
#define HAVE_PIPE
6364
#define _FILE_OFFSET_BITS 64
6465
#endif
65
-#define JIM_VERSION 82
66
+#define JIM_VERSION 83
6667
#ifndef JIM_WIN32COMPAT_H
6768
#define JIM_WIN32COMPAT_H
6869
6970
7071
@@ -574,11 +575,11 @@
574575
575576
typedef struct Jim_Interp {
576577
Jim_Obj *result;
577578
int unused_errorLine;
578579
Jim_Obj *currentFilenameObj;
579
- int unused_addStackTrace;
580
+ int break_level;
580581
int maxCallFrameDepth;
581582
int maxEvalDepth;
582583
int evalDepth;
583584
int returnCode;
584585
int returnLevel;
@@ -716,10 +717,18 @@
716717
int objc, Jim_Obj *const *objv);
717718
#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
718719
JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
719720
JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
720721
Jim_Obj **resObjPtrPtr, int flags);
722
+
723
+
724
+JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
725
+ int *lineptr);
726
+
727
+JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
728
+ Jim_Obj *fileNameObj, int lineNumber);
729
+
721730
722731
723732
JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
724733
JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
725734
JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
@@ -2343,13 +2352,11 @@
23432352
continue;
23442353
}
23452354
if (JimCheckStreamError(interp, af)) {
23462355
return JIM_ERR;
23472356
}
2348
- if (nb || af->timeout) {
2349
- return JIM_OK;
2350
- }
2357
+ break;
23512358
}
23522359
23532360
return JIM_OK;
23542361
}
23552362
@@ -2617,18 +2624,13 @@
26172624
}
26182625
26192626
offset = len;
26202627
len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
26212628
if (len <= 0) {
2622
- if (nb || af->timeout) {
2623
-
2624
- break;
2625
- }
2626
- }
2627
- else {
2628
- Jim_AppendString(interp, af->readbuf, buf, len);
2629
- }
2629
+ break;
2630
+ }
2631
+ Jim_AppendString(interp, af->readbuf, buf, len);
26302632
}
26312633
26322634
aio_set_nonblocking(af, nb);
26332635
26342636
if (!nl && aio_eof(af)) {
@@ -3770,31 +3772,34 @@
37703772
int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
37713773
{
37723774
int regcomp_flags = 0;
37733775
int regexec_flags = 0;
37743776
int opt_all = 0;
3777
+ int opt_command = 0;
37753778
int offset = 0;
37763779
regex_t *regex;
37773780
const char *p;
3778
- int result;
3781
+ int result = JIM_OK;
37793782
regmatch_t pmatch[MAX_SUB_MATCHES + 1];
37803783
int num_matches = 0;
37813784
37823785
int i, j, n;
37833786
Jim_Obj *varname;
37843787
Jim_Obj *resultObj;
3788
+ Jim_Obj *cmd_prefix = NULL;
3789
+ Jim_Obj *regcomp_obj = NULL;
37853790
const char *source_str;
37863791
int source_len;
3787
- const char *replace_str;
3792
+ const char *replace_str = NULL;
37883793
int replace_len;
37893794
const char *pattern;
37903795
int option;
37913796
enum {
3792
- OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
3797
+ OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
37933798
};
37943799
static const char * const options[] = {
3795
- "-nocase", "-line", "-all", "-start", "--", NULL
3800
+ "-nocase", "-line", "-all", "-start", "-command", "--", NULL
37963801
};
37973802
37983803
if (argc < 4) {
37993804
wrongNumArgs:
38003805
Jim_WrongNumArgs(interp, 1, argv,
@@ -3834,24 +3839,43 @@
38343839
}
38353840
if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
38363841
return JIM_ERR;
38373842
}
38383843
break;
3844
+
3845
+ case OPT_COMMAND:
3846
+ opt_command = 1;
3847
+ break;
38393848
}
38403849
}
38413850
if (argc - i != 3 && argc - i != 4) {
38423851
goto wrongNumArgs;
38433852
}
38443853
3845
- regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
3854
+
3855
+ regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
3856
+ Jim_IncrRefCount(regcomp_obj);
3857
+ regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
38463858
if (!regex) {
3859
+ Jim_DecrRefCount(interp, regcomp_obj);
38473860
return JIM_ERR;
38483861
}
38493862
pattern = Jim_String(argv[i]);
38503863
38513864
source_str = Jim_GetString(argv[i + 1], &source_len);
3852
- replace_str = Jim_GetString(argv[i + 2], &replace_len);
3865
+ if (opt_command) {
3866
+ cmd_prefix = argv[i + 2];
3867
+ if (Jim_ListLength(interp, cmd_prefix) == 0) {
3868
+ Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
3869
+ Jim_DecrRefCount(interp, regcomp_obj);
3870
+ return JIM_ERR;
3871
+ }
3872
+ Jim_IncrRefCount(cmd_prefix);
3873
+ }
3874
+ else {
3875
+ replace_str = Jim_GetString(argv[i + 2], &replace_len);
3876
+ }
38533877
varname = argv[i + 3];
38543878
38553879
38563880
resultObj = Jim_NewStringObj(interp, "", 0);
38573881
@@ -3891,39 +3915,62 @@
38913915
38923916
num_matches++;
38933917
38943918
Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
38953919
3896
-
3897
- for (j = 0; j < replace_len; j++) {
3898
- int idx;
3899
- int c = replace_str[j];
3900
-
3901
- if (c == '&') {
3902
- idx = 0;
3903
- }
3904
- else if (c == '\\' && j < replace_len) {
3905
- c = replace_str[++j];
3906
- if ((c >= '0') && (c <= '9')) {
3907
- idx = c - '0';
3908
- }
3909
- else if ((c == '\\') || (c == '&')) {
3910
- Jim_AppendString(interp, resultObj, replace_str + j, 1);
3911
- continue;
3912
- }
3913
- else {
3914
- Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
3915
- continue;
3916
- }
3917
- }
3918
- else {
3919
- Jim_AppendString(interp, resultObj, replace_str + j, 1);
3920
- continue;
3921
- }
3922
- if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
3923
- Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
3924
- pmatch[idx].rm_eo - pmatch[idx].rm_so);
3920
+ if (opt_command) {
3921
+
3922
+ Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
3923
+ for (j = 0; j < MAX_SUB_MATCHES; j++) {
3924
+ if (pmatch[j].rm_so == -1) {
3925
+ break;
3926
+ }
3927
+ else {
3928
+ Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3929
+ Jim_ListAppendElement(interp, cmdListObj, srcObj);
3930
+ }
3931
+ }
3932
+ Jim_IncrRefCount(cmdListObj);
3933
+
3934
+ result = Jim_EvalObj(interp, cmdListObj);
3935
+ Jim_DecrRefCount(interp, cmdListObj);
3936
+ if (result != JIM_OK) {
3937
+ goto cmd_error;
3938
+ }
3939
+ Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
3940
+ }
3941
+ else {
3942
+
3943
+ for (j = 0; j < replace_len; j++) {
3944
+ int idx;
3945
+ int c = replace_str[j];
3946
+
3947
+ if (c == '&') {
3948
+ idx = 0;
3949
+ }
3950
+ else if (c == '\\' && j < replace_len) {
3951
+ c = replace_str[++j];
3952
+ if ((c >= '0') && (c <= '9')) {
3953
+ idx = c - '0';
3954
+ }
3955
+ else if ((c == '\\') || (c == '&')) {
3956
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
3957
+ continue;
3958
+ }
3959
+ else {
3960
+ Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
3961
+ continue;
3962
+ }
3963
+ }
3964
+ else {
3965
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
3966
+ continue;
3967
+ }
3968
+ if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
3969
+ Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
3970
+ pmatch[idx].rm_eo - pmatch[idx].rm_so);
3971
+ }
39253972
}
39263973
}
39273974
39283975
p += pmatch[0].rm_eo;
39293976
n -= pmatch[0].rm_eo;
@@ -3956,25 +4003,37 @@
39564003
39574004
} while (n);
39584005
39594006
Jim_AppendString(interp, resultObj, p, -1);
39604007
3961
-
3962
- if (argc - i == 4) {
3963
- result = Jim_SetVariable(interp, varname, resultObj);
3964
-
3965
- if (result == JIM_OK) {
3966
- Jim_SetResultInt(interp, num_matches);
3967
- }
3968
- else {
3969
- Jim_FreeObj(interp, resultObj);
3970
- }
3971
- }
3972
- else {
3973
- Jim_SetResult(interp, resultObj);
3974
- result = JIM_OK;
3975
- }
4008
+cmd_error:
4009
+ if (result == JIM_OK) {
4010
+
4011
+ if (argc - i == 4) {
4012
+ result = Jim_SetVariable(interp, varname, resultObj);
4013
+
4014
+ if (result == JIM_OK) {
4015
+ Jim_SetResultInt(interp, num_matches);
4016
+ }
4017
+ else {
4018
+ Jim_FreeObj(interp, resultObj);
4019
+ }
4020
+ }
4021
+ else {
4022
+ Jim_SetResult(interp, resultObj);
4023
+ result = JIM_OK;
4024
+ }
4025
+ }
4026
+ else {
4027
+ Jim_FreeObj(interp, resultObj);
4028
+ }
4029
+
4030
+ if (opt_command) {
4031
+ Jim_DecrRefCount(interp, cmd_prefix);
4032
+ }
4033
+
4034
+ Jim_DecrRefCount(interp, regcomp_obj);
39764035
39774036
return result;
39784037
}
39794038
39804039
int Jim_regexpInit(Jim_Interp *interp)
@@ -6353,10 +6412,11 @@
63536412
Jim_SetResultString(interp, "Failed to parse time according to format", -1);
63546413
return JIM_ERR;
63556414
}
63566415
63576416
6417
+ tm.tm_isdst = options.gmt ? 0 : -1;
63586418
Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
63596419
63606420
return JIM_OK;
63616421
}
63626422
#endif
@@ -6732,11 +6792,13 @@
67326792
Jim_arrayInit(interp);
67336793
Jim_stdlibInit(interp);
67346794
Jim_tclcompatInit(interp);
67356795
return JIM_OK;
67366796
}
6797
+#ifndef JIM_TINY
67376798
#define JIM_OPTIMIZATION
6799
+#endif
67386800
67396801
#include <stdio.h>
67406802
#include <stdlib.h>
67416803
67426804
#include <string.h>
@@ -6792,11 +6854,13 @@
67926854
67936855
67946856
67956857
#define JIM_INTEGER_SPACE 24
67966858
6797
-const char *jim_tt_name(int type);
6859
+#if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
6860
+static const char *jim_tt_name(int type);
6861
+#endif
67986862
67996863
#ifdef JIM_DEBUG_PANIC
68006864
static void JimPanicDump(int fail_condition, const char *fmt, ...);
68016865
#define JimPanic(X) JimPanicDump X
68026866
#else
@@ -6828,11 +6892,10 @@
68286892
static int JimSign(jim_wide w);
68296893
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
68306894
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
68316895
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
68326896
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
6833
-static void JimSetErrorStack(Jim_Interp *interp);
68346897
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
68356898
68366899
#define JIM_DICT_SUGAR 100
68376900
68386901
@@ -7807,10 +7870,11 @@
78077870
int tt;
78087871
int eof;
78097872
int inquote;
78107873
int comment;
78117874
struct JimParseMissing missing;
7875
+ const char *errmsg;
78127876
};
78137877
78147878
static int JimParseScript(struct JimParserCtx *pc);
78157879
static int JimParseSep(struct JimParserCtx *pc);
78167880
static int JimParseEol(struct JimParserCtx *pc);
@@ -9507,21 +9571,10 @@
95079571
{
95089572
dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
95099573
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
95109574
}
95119575
9512
-static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9513
- Jim_Obj *fileNameObj, int lineNumber)
9514
-{
9515
- JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
9516
- JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object"));
9517
- Jim_IncrRefCount(fileNameObj);
9518
- objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9519
- objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9520
- objPtr->typePtr = &sourceObjType;
9521
-}
9522
-
95239576
static const Jim_ObjType scriptLineObjType = {
95249577
"scriptline",
95259578
NULL,
95269579
NULL,
95279580
NULL,
@@ -9578,10 +9631,11 @@
95789631
} ScriptObj;
95799632
95809633
static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
95819634
static int JimParseCheckMissing(Jim_Interp *interp, int ch);
95829635
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
9636
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
95839637
95849638
void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
95859639
{
95869640
int i;
95879641
struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
@@ -9793,11 +9847,11 @@
97939847
97949848
token->type = t->type;
97959849
token->objPtr = JimMakeScriptObj(interp, t);
97969850
Jim_IncrRefCount(token->objPtr);
97979851
9798
- JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9852
+ Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
97999853
token++;
98009854
}
98019855
}
98029856
98039857
if (lineargs == 0) {
@@ -9852,10 +9906,43 @@
98529906
}
98539907
98549908
Jim_SetResultString(interp, msg, -1);
98559909
return JIM_ERR;
98569910
}
9911
+
9912
+Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
9913
+{
9914
+ int line;
9915
+ Jim_Obj *fileNameObj;
9916
+
9917
+ if (objPtr->typePtr == &sourceObjType) {
9918
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9919
+ line = objPtr->internalRep.sourceValue.lineNumber;
9920
+ }
9921
+ else if (objPtr->typePtr == &scriptObjType) {
9922
+ ScriptObj *script = JimGetScript(interp, objPtr);
9923
+ fileNameObj = script->fileNameObj;
9924
+ line = script->firstline;
9925
+ }
9926
+ else {
9927
+ fileNameObj = interp->emptyObj;
9928
+ line = 1;
9929
+ }
9930
+ *lineptr = line;
9931
+ return fileNameObj;
9932
+}
9933
+
9934
+void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9935
+ Jim_Obj *fileNameObj, int lineNumber)
9936
+{
9937
+ JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
9938
+ Jim_FreeIntRep(interp, objPtr);
9939
+ Jim_IncrRefCount(fileNameObj);
9940
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9941
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9942
+ objPtr->typePtr = &sourceObjType;
9943
+}
98579944
98589945
static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
98599946
ParseTokenList *tokenlist)
98609947
{
98619948
int i;
@@ -9881,16 +9968,15 @@
98819968
int scriptTextLen;
98829969
const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
98839970
struct JimParserCtx parser;
98849971
struct ScriptObj *script;
98859972
ParseTokenList tokenlist;
9886
- int line = 1;
9973
+ Jim_Obj *fileNameObj;
9974
+ int line;
98879975
98889976
9889
- if (objPtr->typePtr == &sourceObjType) {
9890
- line = objPtr->internalRep.sourceValue.lineNumber;
9891
- }
9977
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
98929978
98939979
98949980
ScriptTokenListInit(&tokenlist);
98959981
98969982
JimParserInit(&parser, scriptText, scriptTextLen, line);
@@ -9905,16 +9991,11 @@
99059991
99069992
99079993
script = Jim_Alloc(sizeof(*script));
99089994
memset(script, 0, sizeof(*script));
99099995
script->inUse = 1;
9910
- if (objPtr->typePtr == &sourceObjType) {
9911
- script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9912
- }
9913
- else {
9914
- script->fileNameObj = interp->emptyObj;
9915
- }
9996
+ script->fileNameObj = fileNameObj;
99169997
Jim_IncrRefCount(script->fileNameObj);
99179998
script->missing = parser.missing.ch;
99189999
script->linenr = parser.missing.line;
991910000
992010001
ScriptObjAddTokens(interp, script, &tokenlist);
@@ -11386,14 +11467,15 @@
1138611467
Jim_DecrRefCount(i, i->unknown);
1138711468
Jim_DecrRefCount(i, i->defer);
1138811469
Jim_DecrRefCount(i, i->nullScriptObj);
1138911470
Jim_DecrRefCount(i, i->currentFilenameObj);
1139011471
11472
+ Jim_FreeHashTable(&i->commands);
11473
+
1139111474
1139211475
Jim_InterpIncrProcEpoch(i);
1139311476
11394
- Jim_FreeHashTable(&i->commands);
1139511477
#ifdef JIM_REFERENCES
1139611478
Jim_FreeHashTable(&i->references);
1139711479
#endif
1139811480
Jim_FreeHashTable(&i->packages);
1139911481
Jim_Free(i->prngState);
@@ -11588,20 +11670,28 @@
1158811670
Jim_DecrRefCount(interp, interp->stackTrace);
1158911671
interp->stackTrace = stackTraceObj;
1159011672
interp->errorFlag = 1;
1159111673
}
1159211674
11593
-static void JimSetErrorStack(Jim_Interp *interp)
11675
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
1159411676
{
1159511677
if (!interp->errorFlag) {
1159611678
int i;
1159711679
Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
1159811680
11599
- for (i = 0; i <= interp->procLevel; i++) {
11600
- Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11601
- if (frame) {
11602
- JimAddStackFrame(interp, frame, stackTrace);
11681
+ if (interp->procLevel == 0 && script) {
11682
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11683
+ Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
11684
+ Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
11685
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11686
+ }
11687
+ else {
11688
+ for (i = 0; i <= interp->procLevel; i++) {
11689
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11690
+ if (frame) {
11691
+ JimAddStackFrame(interp, frame, stackTrace);
11692
+ }
1160311693
}
1160411694
}
1160511695
JimSetStackTrace(interp, stackTrace);
1160611696
}
1160711697
}
@@ -12288,18 +12378,11 @@
1228812378
Jim_Free(dict);
1228912379
return JIM_OK;
1229012380
}
1229112381
1229212382
12293
- if (objPtr->typePtr == &sourceObjType) {
12294
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
12295
- linenr = objPtr->internalRep.sourceValue.lineNumber;
12296
- }
12297
- else {
12298
- fileNameObj = interp->emptyObj;
12299
- linenr = 1;
12300
- }
12383
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
1230112384
Jim_IncrRefCount(fileNameObj);
1230212385
1230312386
1230412387
str = Jim_GetString(objPtr, &strLen);
1230512388
@@ -12317,11 +12400,11 @@
1231712400
1231812401
JimParseList(&parser);
1231912402
if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
1232012403
continue;
1232112404
elementPtr = JimParserGetTokenObj(interp, &parser);
12322
- JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12405
+ Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
1232312406
ListAppendElement(objPtr, elementPtr);
1232412407
}
1232512408
}
1232612409
Jim_DecrRefCount(interp, fileNameObj);
1232712410
return JIM_OK;
@@ -12372,11 +12455,12 @@
1237212455
enum {
1237312456
JIM_LSORT_ASCII,
1237412457
JIM_LSORT_NOCASE,
1237512458
JIM_LSORT_INTEGER,
1237612459
JIM_LSORT_REAL,
12377
- JIM_LSORT_COMMAND
12460
+ JIM_LSORT_COMMAND,
12461
+ JIM_LSORT_DICT
1237812462
} type;
1237912463
int order;
1238012464
Jim_Obj **indexv;
1238112465
int indexc;
1238212466
int unique;
@@ -12404,10 +12488,47 @@
1240412488
1240512489
static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
1240612490
{
1240712491
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
1240812492
}
12493
+
12494
+static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12495
+{
12496
+
12497
+ const char *left = Jim_String(*lhsObj);
12498
+ const char *right = Jim_String(*rhsObj);
12499
+
12500
+ while (1) {
12501
+ if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
12502
+
12503
+ jim_wide lint, rint;
12504
+ char *lend, *rend;
12505
+ lint = jim_strtoull(left, &lend);
12506
+ rint = jim_strtoull(right, &rend);
12507
+ if (lint != rint) {
12508
+ return JimSign(lint - rint) * sort_info->order;
12509
+ }
12510
+ if (lend -left != rend - right) {
12511
+ return JimSign((lend - left) - (rend - right)) * sort_info->order;
12512
+ }
12513
+ left = lend;
12514
+ right = rend;
12515
+ }
12516
+ else {
12517
+ int cl, cr;
12518
+ left += utf8_tounicode_case(left, &cl, 1);
12519
+ right += utf8_tounicode_case(right, &cr, 1);
12520
+ if (cl != cr) {
12521
+ return JimSign(cl - cr) * sort_info->order;
12522
+ }
12523
+ if (cl == 0) {
12524
+
12525
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12526
+ }
12527
+ }
12528
+ }
12529
+}
1240912530
1241012531
static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
1241112532
{
1241212533
jim_wide lhs = 0, rhs = 0;
1241312534
@@ -12519,10 +12640,13 @@
1251912640
fn = ListSortReal;
1252012641
break;
1252112642
case JIM_LSORT_COMMAND:
1252212643
fn = ListSortCommand;
1252312644
break;
12645
+ case JIM_LSORT_DICT:
12646
+ fn = ListSortDict;
12647
+ break;
1252412648
default:
1252512649
fn = NULL;
1252612650
JimPanic((1, "ListSort called with invalid sort type"));
1252712651
return -1;
1252812652
}
@@ -12567,10 +12691,15 @@
1256712691
{
1256812692
int currentLen = listPtr->internalRep.listValue.len;
1256912693
int requiredLen = currentLen + elemc;
1257012694
int i;
1257112695
Jim_Obj **point;
12696
+
12697
+ if (elemc == 0) {
12698
+
12699
+ return;
12700
+ }
1257212701
1257312702
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
1257412703
if (currentLen) {
1257512704
1257612705
requiredLen *= 2;
@@ -14332,10 +14461,12 @@
1433214461
#define JIM_EXPR_OPERATORS_NUM \
1433314462
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
1433414463
1433514464
static int JimParseExpression(struct JimParserCtx *pc)
1433614465
{
14466
+ pc->errmsg = NULL;
14467
+
1433714468
while (1) {
1433814469
1433914470
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
1434014471
if (*pc->p == '\n') {
1434114472
pc->linenr++;
@@ -14382,10 +14513,11 @@
1438214513
if (JimParseVar(pc) == JIM_ERR)
1438314514
return JimParseExprOperator(pc);
1438414515
else {
1438514516
1438614517
if (pc->tt == JIM_TT_EXPRSUGAR) {
14518
+ pc->errmsg = "nesting expr in expr is not allowed";
1438714519
return JIM_ERR;
1438814520
}
1438914521
return JIM_OK;
1439014522
}
1439114523
break;
@@ -14526,10 +14658,11 @@
1452614658
while (len && isspace(UCHAR(*p))) {
1452714659
len--;
1452814660
p++;
1452914661
}
1453014662
if (*p != '(') {
14663
+ pc->errmsg = "function requires parentheses";
1453114664
return JIM_ERR;
1453214665
}
1453314666
}
1453414667
pc->tend = pc->p + bestLen - 1;
1453514668
pc->p += bestLen;
@@ -14537,35 +14670,10 @@
1453714670
1453814671
pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
1453914672
return JIM_OK;
1454014673
}
1454114674
14542
-const char *jim_tt_name(int type)
14543
-{
14544
- static const char * const tt_names[JIM_TT_EXPR_OP] =
14545
- { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
14546
- "DBL", "BOO", "$()" };
14547
- if (type < JIM_TT_EXPR_OP) {
14548
- return tt_names[type];
14549
- }
14550
- else if (type == JIM_EXPROP_UNARYMINUS) {
14551
- return "-VE";
14552
- }
14553
- else if (type == JIM_EXPROP_UNARYPLUS) {
14554
- return "+VE";
14555
- }
14556
- else {
14557
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
14558
- static char buf[20];
14559
-
14560
- if (op->name) {
14561
- return op->name;
14562
- }
14563
- sprintf(buf, "(%d)", type);
14564
- return buf;
14565
- }
14566
-}
1456714675
1456814676
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
1456914677
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
1457014678
static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
1457114679
@@ -14867,11 +14975,11 @@
1486714975
if (!objPtr) {
1486814976
1486914977
objPtr = Jim_NewStringObj(interp, t->token, t->len);
1487014978
if (t->type == JIM_TT_CMD) {
1487114979
14872
- JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
14980
+ Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
1487314981
}
1487414982
}
1487514983
1487614984
1487714985
node = builder->next++;
@@ -14965,18 +15073,11 @@
1496515073
int line;
1496615074
Jim_Obj *fileNameObj;
1496715075
int rc = JIM_ERR;
1496815076
1496915077
14970
- if (objPtr->typePtr == &sourceObjType) {
14971
- fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
14972
- line = objPtr->internalRep.sourceValue.lineNumber;
14973
- }
14974
- else {
14975
- fileNameObj = interp->emptyObj;
14976
- line = 1;
14977
- }
15078
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
1497815079
Jim_IncrRefCount(fileNameObj);
1497915080
1498015081
exprText = Jim_GetString(objPtr, &exprTextLen);
1498115082
1498215083
@@ -14985,10 +15086,13 @@
1498515086
JimParserInit(&parser, exprText, exprTextLen, line);
1498615087
while (!parser.eof) {
1498715088
if (JimParseExpression(&parser) != JIM_OK) {
1498815089
ScriptTokenListFree(&tokenlist);
1498915090
Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
15091
+ if (parser.errmsg) {
15092
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
15093
+ }
1499015094
expr = NULL;
1499115095
goto err;
1499215096
}
1499315097
1499415098
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
@@ -15004,14 +15108,21 @@
1500415108
tokenlist.list[i].len, tokenlist.list[i].token);
1500515109
}
1500615110
}
1500715111
#endif
1500815112
15009
- if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) {
15113
+ if (tokenlist.count <= 1) {
15114
+ Jim_SetResultString(interp, "empty expression", -1);
15115
+ rc = JIM_ERR;
15116
+ }
15117
+ else {
15118
+ rc = JimParseCheckMissing(interp, parser.missing.ch);
15119
+ }
15120
+ if (rc != JIM_OK) {
1501015121
ScriptTokenListFree(&tokenlist);
1501115122
Jim_DecrRefCount(interp, fileNameObj);
15012
- return JIM_ERR;
15123
+ return rc;
1501315124
}
1501415125
1501515126
1501615127
expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
1501715128
@@ -15858,17 +15969,22 @@
1585815969
1585915970
int ret;
1586015971
Jim_Obj *nargv[7];
1586115972
Jim_Obj *traceCmdObj = interp->traceCmdObj;
1586215973
Jim_Obj *resultObj = Jim_GetResult(interp);
15974
+ ScriptObj *script = NULL;
1586315975
15864
- ScriptObj *script = JimGetScript(interp, interp->evalFrame->scriptObj);
15976
+
15977
+
15978
+ if (interp->evalFrame->scriptObj) {
15979
+ script = JimGetScript(interp, interp->evalFrame->scriptObj);
15980
+ }
1586515981
1586615982
nargv[0] = traceCmdObj;
1586715983
nargv[1] = Jim_NewStringObj(interp, type, -1);
15868
- nargv[2] = script->fileNameObj;
15869
- nargv[3] = Jim_NewIntObj(interp, script->linenr);
15984
+ nargv[2] = script ? script->fileNameObj : interp->emptyObj;
15985
+ nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
1587015986
nargv[4] = resultObj;
1587115987
nargv[5] = argv[0];
1587215988
nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
1587315989
1587415990
@@ -15986,11 +16102,11 @@
1598616102
else {
1598716103
interp->cmdPrivData = cmdPtr->u.native.privData;
1598816104
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
1598916105
}
1599016106
if (retcode == JIM_ERR) {
15991
- JimSetErrorStack(interp);
16107
+ JimSetErrorStack(interp, NULL);
1599216108
}
1599316109
}
1599416110
1599516111
if (tailcallObj) {
1599616112
@@ -16021,11 +16137,11 @@
1602116137
1602216138
out:
1602316139
JimDecrCmdRefCount(interp, cmdPtr);
1602416140
1602516141
if (retcode == JIM_ERR) {
16026
- JimSetErrorStack(interp);
16142
+ JimSetErrorStack(interp, NULL);
1602716143
}
1602816144
1602916145
if (interp->framePtr->tailcallObj) {
1603016146
JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
1603116147
Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
@@ -16042,10 +16158,11 @@
1604216158
Jim_EvalFrame frame;
1604316159
1604416160
1604516161
for (i = 0; i < objc; i++)
1604616162
Jim_IncrRefCount(objv[i]);
16163
+
1604716164
1604816165
JimPushEvalFrame(interp, &frame, NULL);
1604916166
1605016167
retcode = JimInvokeCommand(interp, objc, objv);
1605116168
@@ -16181,11 +16298,13 @@
1618116298
objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
1618216299
Jim_IncrRefCount(intv[2]);
1618316300
}
1618416301
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
1618516302
16186
- JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
16303
+ int line;
16304
+ Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
16305
+ Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
1618716306
}
1618816307
1618916308
1619016309
s = objPtr->bytes = Jim_Alloc(totlen + 1);
1619116310
objPtr->length = totlen;
@@ -16248,11 +16367,11 @@
1624816367
}
1624916368
1625016369
Jim_IncrRefCount(scriptObjPtr);
1625116370
script = JimGetScript(interp, scriptObjPtr);
1625216371
if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16253
- JimSetErrorStack(interp);
16372
+ JimSetErrorStack(interp, script);
1625416373
Jim_DecrRefCount(interp, scriptObjPtr);
1625516374
return JIM_ERR;
1625616375
}
1625716376
1625816377
Jim_SetEmptyResult(interp);
@@ -16420,11 +16539,11 @@
1642016539
}
1642116540
}
1642216541
1642316542
1642416543
if (retcode == JIM_ERR) {
16425
- JimSetErrorStack(interp);
16544
+ JimSetErrorStack(interp, NULL);
1642616545
}
1642716546
1642816547
JimPopEvalFrame(interp);
1642916548
1643016549
Jim_FreeIntRep(interp, scriptObjPtr);
@@ -16648,11 +16767,11 @@
1664816767
Jim_Obj *scriptObjPtr;
1664916768
1665016769
scriptObjPtr = Jim_NewStringObj(interp, script, -1);
1665116770
Jim_IncrRefCount(scriptObjPtr);
1665216771
if (filename) {
16653
- JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16772
+ Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
1665416773
}
1665516774
retval = Jim_EvalObj(interp, scriptObjPtr);
1665616775
Jim_DecrRefCount(interp, scriptObjPtr);
1665716776
return retval;
1665816777
}
@@ -16730,11 +16849,11 @@
1673016849
if (!scriptObjPtr) {
1673116850
return JIM_ERR;
1673216851
}
1673316852
1673416853
filenameObj = Jim_NewStringObj(interp, filename, -1);
16735
- JimSetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16854
+ Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
1673616855
1673716856
oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
1673816857
1673916858
retcode = Jim_EvalObj(interp, scriptObjPtr);
1674016859
@@ -16771,11 +16890,13 @@
1677116890
if (JimParseVar(pc) == JIM_OK) {
1677216891
return;
1677316892
}
1677416893
1677516894
pc->tstart = pc->p;
16776
- flags |= JIM_SUBST_NOVAR;
16895
+
16896
+ pc->p++;
16897
+ pc->len--;
1677716898
}
1677816899
while (pc->len) {
1677916900
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
1678016901
break;
1678116902
}
@@ -17274,11 +17395,11 @@
1727417395
}
1727517396
1727617397
static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
1727717398
{
1727817399
if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17279
- if (--interp->returnLevel > 0) {
17400
+ if (--interp->break_level > 0) {
1728017401
return 1;
1728117402
}
1728217403
}
1728317404
return 0;
1728417405
}
@@ -17464,19 +17585,18 @@
1746417585
#endif
1746517586
1746617587
while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
1746717588
1746817589
retval = Jim_EvalObj(interp, argv[4]);
17469
-
17590
+ if (JimCheckLoopRetcode(interp, retval)) {
17591
+ immediate++;
17592
+ break;
17593
+ }
1747017594
if (retval == JIM_OK || retval == JIM_CONTINUE) {
1747117595
1747217596
JIM_IF_OPTIM(evalnext:)
1747317597
retval = Jim_EvalObj(interp, argv[3]);
17474
- if (JimCheckLoopRetcode(interp, retval)) {
17475
- immediate++;
17476
- goto out;
17477
- }
1747817598
if (retval == JIM_OK || retval == JIM_CONTINUE) {
1747917599
1748017600
JIM_IF_OPTIM(testcond:)
1748117601
retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
1748217602
}
@@ -18327,21 +18447,23 @@
1832718447
1832818448
static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
1832918449
{
1833018450
static const char * const options[] = {
1833118451
"-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18332
- "-stride", NULL
18452
+ "-stride", "-dictionary", NULL
1833318453
};
1833418454
enum {
1833518455
OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18336
- OPT_STRIDE
18456
+ OPT_STRIDE, OPT_DICT
1833718457
};
1833818458
Jim_Obj *resObj;
1833918459
int i;
1834018460
int retCode;
1834118461
int shared;
1834218462
long stride = 1;
18463
+ Jim_Obj **elements;
18464
+ int listlen;
1834318465
1834418466
struct lsort_info info;
1834518467
1834618468
if (argc < 2) {
1834718469
wrongargs:
@@ -18364,10 +18486,13 @@
1836418486
return JIM_ERR;
1836518487
switch (option) {
1836618488
case OPT_ASCII:
1836718489
info.type = JIM_LSORT_ASCII;
1836818490
break;
18491
+ case OPT_DICT:
18492
+ info.type = JIM_LSORT_DICT;
18493
+ break;
1836918494
case OPT_NOCASE:
1837018495
info.type = JIM_LSORT_NOCASE;
1837118496
break;
1837218497
case OPT_INTEGER:
1837318498
info.type = JIM_LSORT_INTEGER;
@@ -18418,17 +18543,21 @@
1841818543
i++;
1841918544
break;
1842018545
}
1842118546
}
1842218547
resObj = argv[argc - 1];
18548
+ JimListGetElements(interp, resObj, &listlen, &elements);
18549
+ if (listlen <= 1) {
18550
+
18551
+ Jim_SetResult(interp, resObj);
18552
+ return JIM_OK;
18553
+ }
18554
+
1842318555
if (stride > 1) {
1842418556
Jim_Obj *tmpListObj;
18425
- Jim_Obj **elements;
18426
- int listlen;
1842718557
int i;
1842818558
18429
- JimListGetElements(interp, resObj, &listlen, &elements);
1843018559
if (listlen % stride) {
1843118560
Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
1843218561
return JIM_ERR;
1843318562
}
1843418563
@@ -18612,11 +18741,11 @@
1861218741
long level;
1861318742
int ret = Jim_GetLong(interp, argv[1], &level);
1861418743
if (ret != JIM_OK) {
1861518744
return ret;
1861618745
}
18617
- interp->returnLevel = level;
18746
+ interp->break_level = level;
1861818747
}
1861918748
return retcode;
1862018749
}
1862118750
1862218751
@@ -20330,39 +20459,28 @@
2033020459
}
2033120460
Jim_SetResult(interp, interp->currentFilenameObj);
2033220461
return JIM_OK;
2033320462
2033420463
case INFO_SOURCE:{
20335
- jim_wide line;
2033620464
Jim_Obj *resObjPtr;
2033720465
Jim_Obj *fileNameObj;
2033820466
2033920467
if (argc == 4) {
2034020468
Jim_SubCmdArgError(interp, ct, argv[0]);
2034120469
return JIM_ERR;
2034220470
}
2034320471
if (argc == 5) {
20472
+ jim_wide line;
2034420473
if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
2034520474
return JIM_ERR;
2034620475
}
2034720476
resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20348
- JimSetSourceInfo(interp, resObjPtr, argv[3], line);
20349
- }
20350
- else {
20351
- if (argv[2]->typePtr == &sourceObjType) {
20352
- fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
20353
- line = argv[2]->internalRep.sourceValue.lineNumber;
20354
- }
20355
- else if (argv[2]->typePtr == &scriptObjType) {
20356
- ScriptObj *script = JimGetScript(interp, argv[2]);
20357
- fileNameObj = script->fileNameObj;
20358
- line = script->firstline;
20359
- }
20360
- else {
20361
- fileNameObj = interp->emptyObj;
20362
- line = 1;
20363
- }
20477
+ Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
20478
+ }
20479
+ else {
20480
+ int line;
20481
+ fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
2036420482
resObjPtr = Jim_NewListObj(interp, NULL, 0);
2036520483
Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
2036620484
Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
2036720485
}
2036820486
Jim_SetResult(interp, resObjPtr);
@@ -23644,11 +23762,13 @@
2364423762
else {
2364523763
filenameObj = Jim_NewStringObj(interp, filename_template, -1);
2364623764
}
2364723765
2364823766
23767
+#ifdef HAVE_UMASK
2364923768
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
23769
+#endif
2365023770
#ifdef HAVE_MKSTEMP
2365123771
fd = mkstemp(filenameObj->bytes);
2365223772
#else
2365323773
if (mktemp(filenameObj->bytes) == NULL) {
2365423774
fd = -1;
@@ -23655,11 +23775,13 @@
2365523775
}
2365623776
else {
2365723777
fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
2365823778
}
2365923779
#endif
23780
+#ifdef HAVE_UMASK
2366023781
umask(mask);
23782
+#endif
2366123783
if (fd < 0) {
2366223784
Jim_SetResultErrno(interp, Jim_String(filenameObj));
2366323785
Jim_FreeNewObj(interp, filenameObj);
2366423786
return -1;
2366523787
}
@@ -24258,10 +24380,15 @@
2425824380
JimPrintErrorMessage(interp);
2425924381
}
2426024382
2426124383
Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
2426224384
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
24385
+#ifdef USE_LINENOISE
24386
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
24387
+#else
24388
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
24389
+#endif
2426324390
retcode = Jim_initjimshInit(interp);
2426424391
2426524392
if (argc == 1) {
2426624393
2426724394
if (retcode == JIM_ERR) {
2426824395
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,10 +1,11 @@
1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2 #define JIM_TCL_COMPAT
3 #define JIM_ANSIC
4 #define JIM_REGEXP
5 #define HAVE_NO_AUTOCONF
 
6 #define _JIMAUTOCONF_H
7 #define TCL_LIBRARY "."
8 #define jim_ext_bootstrap
9 #define jim_ext_aio
10 #define jim_ext_readdir
@@ -60,11 +61,11 @@
60 #define HAVE_UNISTD_H
61 #define HAVE_UMASK
62 #define HAVE_PIPE
63 #define _FILE_OFFSET_BITS 64
64 #endif
65 #define JIM_VERSION 82
66 #ifndef JIM_WIN32COMPAT_H
67 #define JIM_WIN32COMPAT_H
68
69
70
@@ -574,11 +575,11 @@
574
575 typedef struct Jim_Interp {
576 Jim_Obj *result;
577 int unused_errorLine;
578 Jim_Obj *currentFilenameObj;
579 int unused_addStackTrace;
580 int maxCallFrameDepth;
581 int maxEvalDepth;
582 int evalDepth;
583 int returnCode;
584 int returnLevel;
@@ -716,10 +717,18 @@
716 int objc, Jim_Obj *const *objv);
717 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
718 JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
719 JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
720 Jim_Obj **resObjPtrPtr, int flags);
 
 
 
 
 
 
 
 
721
722
723 JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
724 JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
725 JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
@@ -2343,13 +2352,11 @@
2343 continue;
2344 }
2345 if (JimCheckStreamError(interp, af)) {
2346 return JIM_ERR;
2347 }
2348 if (nb || af->timeout) {
2349 return JIM_OK;
2350 }
2351 }
2352
2353 return JIM_OK;
2354 }
2355
@@ -2617,18 +2624,13 @@
2617 }
2618
2619 offset = len;
2620 len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
2621 if (len <= 0) {
2622 if (nb || af->timeout) {
2623
2624 break;
2625 }
2626 }
2627 else {
2628 Jim_AppendString(interp, af->readbuf, buf, len);
2629 }
2630 }
2631
2632 aio_set_nonblocking(af, nb);
2633
2634 if (!nl && aio_eof(af)) {
@@ -3770,31 +3772,34 @@
3770 int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3771 {
3772 int regcomp_flags = 0;
3773 int regexec_flags = 0;
3774 int opt_all = 0;
 
3775 int offset = 0;
3776 regex_t *regex;
3777 const char *p;
3778 int result;
3779 regmatch_t pmatch[MAX_SUB_MATCHES + 1];
3780 int num_matches = 0;
3781
3782 int i, j, n;
3783 Jim_Obj *varname;
3784 Jim_Obj *resultObj;
 
 
3785 const char *source_str;
3786 int source_len;
3787 const char *replace_str;
3788 int replace_len;
3789 const char *pattern;
3790 int option;
3791 enum {
3792 OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
3793 };
3794 static const char * const options[] = {
3795 "-nocase", "-line", "-all", "-start", "--", NULL
3796 };
3797
3798 if (argc < 4) {
3799 wrongNumArgs:
3800 Jim_WrongNumArgs(interp, 1, argv,
@@ -3834,24 +3839,43 @@
3834 }
3835 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3836 return JIM_ERR;
3837 }
3838 break;
 
 
 
 
3839 }
3840 }
3841 if (argc - i != 3 && argc - i != 4) {
3842 goto wrongNumArgs;
3843 }
3844
3845 regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
 
 
 
3846 if (!regex) {
 
3847 return JIM_ERR;
3848 }
3849 pattern = Jim_String(argv[i]);
3850
3851 source_str = Jim_GetString(argv[i + 1], &source_len);
3852 replace_str = Jim_GetString(argv[i + 2], &replace_len);
 
 
 
 
 
 
 
 
 
 
 
3853 varname = argv[i + 3];
3854
3855
3856 resultObj = Jim_NewStringObj(interp, "", 0);
3857
@@ -3891,39 +3915,62 @@
3891
3892 num_matches++;
3893
3894 Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
3895
3896
3897 for (j = 0; j < replace_len; j++) {
3898 int idx;
3899 int c = replace_str[j];
3900
3901 if (c == '&') {
3902 idx = 0;
3903 }
3904 else if (c == '\\' && j < replace_len) {
3905 c = replace_str[++j];
3906 if ((c >= '0') && (c <= '9')) {
3907 idx = c - '0';
3908 }
3909 else if ((c == '\\') || (c == '&')) {
3910 Jim_AppendString(interp, resultObj, replace_str + j, 1);
3911 continue;
3912 }
3913 else {
3914 Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
3915 continue;
3916 }
3917 }
3918 else {
3919 Jim_AppendString(interp, resultObj, replace_str + j, 1);
3920 continue;
3921 }
3922 if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
3923 Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
3924 pmatch[idx].rm_eo - pmatch[idx].rm_so);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3925 }
3926 }
3927
3928 p += pmatch[0].rm_eo;
3929 n -= pmatch[0].rm_eo;
@@ -3956,25 +4003,37 @@
3956
3957 } while (n);
3958
3959 Jim_AppendString(interp, resultObj, p, -1);
3960
3961
3962 if (argc - i == 4) {
3963 result = Jim_SetVariable(interp, varname, resultObj);
3964
3965 if (result == JIM_OK) {
3966 Jim_SetResultInt(interp, num_matches);
3967 }
3968 else {
3969 Jim_FreeObj(interp, resultObj);
3970 }
3971 }
3972 else {
3973 Jim_SetResult(interp, resultObj);
3974 result = JIM_OK;
3975 }
 
 
 
 
 
 
 
 
 
 
 
 
3976
3977 return result;
3978 }
3979
3980 int Jim_regexpInit(Jim_Interp *interp)
@@ -6353,10 +6412,11 @@
6353 Jim_SetResultString(interp, "Failed to parse time according to format", -1);
6354 return JIM_ERR;
6355 }
6356
6357
 
6358 Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
6359
6360 return JIM_OK;
6361 }
6362 #endif
@@ -6732,11 +6792,13 @@
6732 Jim_arrayInit(interp);
6733 Jim_stdlibInit(interp);
6734 Jim_tclcompatInit(interp);
6735 return JIM_OK;
6736 }
 
6737 #define JIM_OPTIMIZATION
 
6738
6739 #include <stdio.h>
6740 #include <stdlib.h>
6741
6742 #include <string.h>
@@ -6792,11 +6854,13 @@
6792
6793
6794
6795 #define JIM_INTEGER_SPACE 24
6796
6797 const char *jim_tt_name(int type);
 
 
6798
6799 #ifdef JIM_DEBUG_PANIC
6800 static void JimPanicDump(int fail_condition, const char *fmt, ...);
6801 #define JimPanic(X) JimPanicDump X
6802 #else
@@ -6828,11 +6892,10 @@
6828 static int JimSign(jim_wide w);
6829 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
6830 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
6831 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
6832 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
6833 static void JimSetErrorStack(Jim_Interp *interp);
6834 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
6835
6836 #define JIM_DICT_SUGAR 100
6837
6838
@@ -7807,10 +7870,11 @@
7807 int tt;
7808 int eof;
7809 int inquote;
7810 int comment;
7811 struct JimParseMissing missing;
 
7812 };
7813
7814 static int JimParseScript(struct JimParserCtx *pc);
7815 static int JimParseSep(struct JimParserCtx *pc);
7816 static int JimParseEol(struct JimParserCtx *pc);
@@ -9507,21 +9571,10 @@
9507 {
9508 dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
9509 Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
9510 }
9511
9512 static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9513 Jim_Obj *fileNameObj, int lineNumber)
9514 {
9515 JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
9516 JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typed object"));
9517 Jim_IncrRefCount(fileNameObj);
9518 objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9519 objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9520 objPtr->typePtr = &sourceObjType;
9521 }
9522
9523 static const Jim_ObjType scriptLineObjType = {
9524 "scriptline",
9525 NULL,
9526 NULL,
9527 NULL,
@@ -9578,10 +9631,11 @@
9578 } ScriptObj;
9579
9580 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9581 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
9582 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
 
9583
9584 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9585 {
9586 int i;
9587 struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
@@ -9793,11 +9847,11 @@
9793
9794 token->type = t->type;
9795 token->objPtr = JimMakeScriptObj(interp, t);
9796 Jim_IncrRefCount(token->objPtr);
9797
9798 JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9799 token++;
9800 }
9801 }
9802
9803 if (lineargs == 0) {
@@ -9852,10 +9906,43 @@
9852 }
9853
9854 Jim_SetResultString(interp, msg, -1);
9855 return JIM_ERR;
9856 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9857
9858 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9859 ParseTokenList *tokenlist)
9860 {
9861 int i;
@@ -9881,16 +9968,15 @@
9881 int scriptTextLen;
9882 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
9883 struct JimParserCtx parser;
9884 struct ScriptObj *script;
9885 ParseTokenList tokenlist;
9886 int line = 1;
 
9887
9888
9889 if (objPtr->typePtr == &sourceObjType) {
9890 line = objPtr->internalRep.sourceValue.lineNumber;
9891 }
9892
9893
9894 ScriptTokenListInit(&tokenlist);
9895
9896 JimParserInit(&parser, scriptText, scriptTextLen, line);
@@ -9905,16 +9991,11 @@
9905
9906
9907 script = Jim_Alloc(sizeof(*script));
9908 memset(script, 0, sizeof(*script));
9909 script->inUse = 1;
9910 if (objPtr->typePtr == &sourceObjType) {
9911 script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9912 }
9913 else {
9914 script->fileNameObj = interp->emptyObj;
9915 }
9916 Jim_IncrRefCount(script->fileNameObj);
9917 script->missing = parser.missing.ch;
9918 script->linenr = parser.missing.line;
9919
9920 ScriptObjAddTokens(interp, script, &tokenlist);
@@ -11386,14 +11467,15 @@
11386 Jim_DecrRefCount(i, i->unknown);
11387 Jim_DecrRefCount(i, i->defer);
11388 Jim_DecrRefCount(i, i->nullScriptObj);
11389 Jim_DecrRefCount(i, i->currentFilenameObj);
11390
 
 
11391
11392 Jim_InterpIncrProcEpoch(i);
11393
11394 Jim_FreeHashTable(&i->commands);
11395 #ifdef JIM_REFERENCES
11396 Jim_FreeHashTable(&i->references);
11397 #endif
11398 Jim_FreeHashTable(&i->packages);
11399 Jim_Free(i->prngState);
@@ -11588,20 +11670,28 @@
11588 Jim_DecrRefCount(interp, interp->stackTrace);
11589 interp->stackTrace = stackTraceObj;
11590 interp->errorFlag = 1;
11591 }
11592
11593 static void JimSetErrorStack(Jim_Interp *interp)
11594 {
11595 if (!interp->errorFlag) {
11596 int i;
11597 Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
11598
11599 for (i = 0; i <= interp->procLevel; i++) {
11600 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11601 if (frame) {
11602 JimAddStackFrame(interp, frame, stackTrace);
 
 
 
 
 
 
 
 
11603 }
11604 }
11605 JimSetStackTrace(interp, stackTrace);
11606 }
11607 }
@@ -12288,18 +12378,11 @@
12288 Jim_Free(dict);
12289 return JIM_OK;
12290 }
12291
12292
12293 if (objPtr->typePtr == &sourceObjType) {
12294 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
12295 linenr = objPtr->internalRep.sourceValue.lineNumber;
12296 }
12297 else {
12298 fileNameObj = interp->emptyObj;
12299 linenr = 1;
12300 }
12301 Jim_IncrRefCount(fileNameObj);
12302
12303
12304 str = Jim_GetString(objPtr, &strLen);
12305
@@ -12317,11 +12400,11 @@
12317
12318 JimParseList(&parser);
12319 if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
12320 continue;
12321 elementPtr = JimParserGetTokenObj(interp, &parser);
12322 JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12323 ListAppendElement(objPtr, elementPtr);
12324 }
12325 }
12326 Jim_DecrRefCount(interp, fileNameObj);
12327 return JIM_OK;
@@ -12372,11 +12455,12 @@
12372 enum {
12373 JIM_LSORT_ASCII,
12374 JIM_LSORT_NOCASE,
12375 JIM_LSORT_INTEGER,
12376 JIM_LSORT_REAL,
12377 JIM_LSORT_COMMAND
 
12378 } type;
12379 int order;
12380 Jim_Obj **indexv;
12381 int indexc;
12382 int unique;
@@ -12404,10 +12488,47 @@
12404
12405 static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12406 {
12407 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
12408 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12409
12410 static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12411 {
12412 jim_wide lhs = 0, rhs = 0;
12413
@@ -12519,10 +12640,13 @@
12519 fn = ListSortReal;
12520 break;
12521 case JIM_LSORT_COMMAND:
12522 fn = ListSortCommand;
12523 break;
 
 
 
12524 default:
12525 fn = NULL;
12526 JimPanic((1, "ListSort called with invalid sort type"));
12527 return -1;
12528 }
@@ -12567,10 +12691,15 @@
12567 {
12568 int currentLen = listPtr->internalRep.listValue.len;
12569 int requiredLen = currentLen + elemc;
12570 int i;
12571 Jim_Obj **point;
 
 
 
 
 
12572
12573 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
12574 if (currentLen) {
12575
12576 requiredLen *= 2;
@@ -14332,10 +14461,12 @@
14332 #define JIM_EXPR_OPERATORS_NUM \
14333 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
14334
14335 static int JimParseExpression(struct JimParserCtx *pc)
14336 {
 
 
14337 while (1) {
14338
14339 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
14340 if (*pc->p == '\n') {
14341 pc->linenr++;
@@ -14382,10 +14513,11 @@
14382 if (JimParseVar(pc) == JIM_ERR)
14383 return JimParseExprOperator(pc);
14384 else {
14385
14386 if (pc->tt == JIM_TT_EXPRSUGAR) {
 
14387 return JIM_ERR;
14388 }
14389 return JIM_OK;
14390 }
14391 break;
@@ -14526,10 +14658,11 @@
14526 while (len && isspace(UCHAR(*p))) {
14527 len--;
14528 p++;
14529 }
14530 if (*p != '(') {
 
14531 return JIM_ERR;
14532 }
14533 }
14534 pc->tend = pc->p + bestLen - 1;
14535 pc->p += bestLen;
@@ -14537,35 +14670,10 @@
14537
14538 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
14539 return JIM_OK;
14540 }
14541
14542 const char *jim_tt_name(int type)
14543 {
14544 static const char * const tt_names[JIM_TT_EXPR_OP] =
14545 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
14546 "DBL", "BOO", "$()" };
14547 if (type < JIM_TT_EXPR_OP) {
14548 return tt_names[type];
14549 }
14550 else if (type == JIM_EXPROP_UNARYMINUS) {
14551 return "-VE";
14552 }
14553 else if (type == JIM_EXPROP_UNARYPLUS) {
14554 return "+VE";
14555 }
14556 else {
14557 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
14558 static char buf[20];
14559
14560 if (op->name) {
14561 return op->name;
14562 }
14563 sprintf(buf, "(%d)", type);
14564 return buf;
14565 }
14566 }
14567
14568 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14569 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
14570 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
14571
@@ -14867,11 +14975,11 @@
14867 if (!objPtr) {
14868
14869 objPtr = Jim_NewStringObj(interp, t->token, t->len);
14870 if (t->type == JIM_TT_CMD) {
14871
14872 JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
14873 }
14874 }
14875
14876
14877 node = builder->next++;
@@ -14965,18 +15073,11 @@
14965 int line;
14966 Jim_Obj *fileNameObj;
14967 int rc = JIM_ERR;
14968
14969
14970 if (objPtr->typePtr == &sourceObjType) {
14971 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
14972 line = objPtr->internalRep.sourceValue.lineNumber;
14973 }
14974 else {
14975 fileNameObj = interp->emptyObj;
14976 line = 1;
14977 }
14978 Jim_IncrRefCount(fileNameObj);
14979
14980 exprText = Jim_GetString(objPtr, &exprTextLen);
14981
14982
@@ -14985,10 +15086,13 @@
14985 JimParserInit(&parser, exprText, exprTextLen, line);
14986 while (!parser.eof) {
14987 if (JimParseExpression(&parser) != JIM_OK) {
14988 ScriptTokenListFree(&tokenlist);
14989 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
 
 
 
14990 expr = NULL;
14991 goto err;
14992 }
14993
14994 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
@@ -15004,14 +15108,21 @@
15004 tokenlist.list[i].len, tokenlist.list[i].token);
15005 }
15006 }
15007 #endif
15008
15009 if (JimParseCheckMissing(interp, parser.missing.ch) == JIM_ERR) {
 
 
 
 
 
 
 
15010 ScriptTokenListFree(&tokenlist);
15011 Jim_DecrRefCount(interp, fileNameObj);
15012 return JIM_ERR;
15013 }
15014
15015
15016 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
15017
@@ -15858,17 +15969,22 @@
15858
15859 int ret;
15860 Jim_Obj *nargv[7];
15861 Jim_Obj *traceCmdObj = interp->traceCmdObj;
15862 Jim_Obj *resultObj = Jim_GetResult(interp);
 
15863
15864 ScriptObj *script = JimGetScript(interp, interp->evalFrame->scriptObj);
 
 
 
 
15865
15866 nargv[0] = traceCmdObj;
15867 nargv[1] = Jim_NewStringObj(interp, type, -1);
15868 nargv[2] = script->fileNameObj;
15869 nargv[3] = Jim_NewIntObj(interp, script->linenr);
15870 nargv[4] = resultObj;
15871 nargv[5] = argv[0];
15872 nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
15873
15874
@@ -15986,11 +16102,11 @@
15986 else {
15987 interp->cmdPrivData = cmdPtr->u.native.privData;
15988 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
15989 }
15990 if (retcode == JIM_ERR) {
15991 JimSetErrorStack(interp);
15992 }
15993 }
15994
15995 if (tailcallObj) {
15996
@@ -16021,11 +16137,11 @@
16021
16022 out:
16023 JimDecrCmdRefCount(interp, cmdPtr);
16024
16025 if (retcode == JIM_ERR) {
16026 JimSetErrorStack(interp);
16027 }
16028
16029 if (interp->framePtr->tailcallObj) {
16030 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
16031 Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
@@ -16042,10 +16158,11 @@
16042 Jim_EvalFrame frame;
16043
16044
16045 for (i = 0; i < objc; i++)
16046 Jim_IncrRefCount(objv[i]);
 
16047
16048 JimPushEvalFrame(interp, &frame, NULL);
16049
16050 retcode = JimInvokeCommand(interp, objc, objv);
16051
@@ -16181,11 +16298,13 @@
16181 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
16182 Jim_IncrRefCount(intv[2]);
16183 }
16184 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
16185
16186 JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
 
 
16187 }
16188
16189
16190 s = objPtr->bytes = Jim_Alloc(totlen + 1);
16191 objPtr->length = totlen;
@@ -16248,11 +16367,11 @@
16248 }
16249
16250 Jim_IncrRefCount(scriptObjPtr);
16251 script = JimGetScript(interp, scriptObjPtr);
16252 if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16253 JimSetErrorStack(interp);
16254 Jim_DecrRefCount(interp, scriptObjPtr);
16255 return JIM_ERR;
16256 }
16257
16258 Jim_SetEmptyResult(interp);
@@ -16420,11 +16539,11 @@
16420 }
16421 }
16422
16423
16424 if (retcode == JIM_ERR) {
16425 JimSetErrorStack(interp);
16426 }
16427
16428 JimPopEvalFrame(interp);
16429
16430 Jim_FreeIntRep(interp, scriptObjPtr);
@@ -16648,11 +16767,11 @@
16648 Jim_Obj *scriptObjPtr;
16649
16650 scriptObjPtr = Jim_NewStringObj(interp, script, -1);
16651 Jim_IncrRefCount(scriptObjPtr);
16652 if (filename) {
16653 JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16654 }
16655 retval = Jim_EvalObj(interp, scriptObjPtr);
16656 Jim_DecrRefCount(interp, scriptObjPtr);
16657 return retval;
16658 }
@@ -16730,11 +16849,11 @@
16730 if (!scriptObjPtr) {
16731 return JIM_ERR;
16732 }
16733
16734 filenameObj = Jim_NewStringObj(interp, filename, -1);
16735 JimSetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16736
16737 oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
16738
16739 retcode = Jim_EvalObj(interp, scriptObjPtr);
16740
@@ -16771,11 +16890,13 @@
16771 if (JimParseVar(pc) == JIM_OK) {
16772 return;
16773 }
16774
16775 pc->tstart = pc->p;
16776 flags |= JIM_SUBST_NOVAR;
 
 
16777 }
16778 while (pc->len) {
16779 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16780 break;
16781 }
@@ -17274,11 +17395,11 @@
17274 }
17275
17276 static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
17277 {
17278 if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17279 if (--interp->returnLevel > 0) {
17280 return 1;
17281 }
17282 }
17283 return 0;
17284 }
@@ -17464,19 +17585,18 @@
17464 #endif
17465
17466 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
17467
17468 retval = Jim_EvalObj(interp, argv[4]);
17469
 
 
 
17470 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17471
17472 JIM_IF_OPTIM(evalnext:)
17473 retval = Jim_EvalObj(interp, argv[3]);
17474 if (JimCheckLoopRetcode(interp, retval)) {
17475 immediate++;
17476 goto out;
17477 }
17478 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17479
17480 JIM_IF_OPTIM(testcond:)
17481 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17482 }
@@ -18327,21 +18447,23 @@
18327
18328 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
18329 {
18330 static const char * const options[] = {
18331 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18332 "-stride", NULL
18333 };
18334 enum {
18335 OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18336 OPT_STRIDE
18337 };
18338 Jim_Obj *resObj;
18339 int i;
18340 int retCode;
18341 int shared;
18342 long stride = 1;
 
 
18343
18344 struct lsort_info info;
18345
18346 if (argc < 2) {
18347 wrongargs:
@@ -18364,10 +18486,13 @@
18364 return JIM_ERR;
18365 switch (option) {
18366 case OPT_ASCII:
18367 info.type = JIM_LSORT_ASCII;
18368 break;
 
 
 
18369 case OPT_NOCASE:
18370 info.type = JIM_LSORT_NOCASE;
18371 break;
18372 case OPT_INTEGER:
18373 info.type = JIM_LSORT_INTEGER;
@@ -18418,17 +18543,21 @@
18418 i++;
18419 break;
18420 }
18421 }
18422 resObj = argv[argc - 1];
 
 
 
 
 
 
 
18423 if (stride > 1) {
18424 Jim_Obj *tmpListObj;
18425 Jim_Obj **elements;
18426 int listlen;
18427 int i;
18428
18429 JimListGetElements(interp, resObj, &listlen, &elements);
18430 if (listlen % stride) {
18431 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18432 return JIM_ERR;
18433 }
18434
@@ -18612,11 +18741,11 @@
18612 long level;
18613 int ret = Jim_GetLong(interp, argv[1], &level);
18614 if (ret != JIM_OK) {
18615 return ret;
18616 }
18617 interp->returnLevel = level;
18618 }
18619 return retcode;
18620 }
18621
18622
@@ -20330,39 +20459,28 @@
20330 }
20331 Jim_SetResult(interp, interp->currentFilenameObj);
20332 return JIM_OK;
20333
20334 case INFO_SOURCE:{
20335 jim_wide line;
20336 Jim_Obj *resObjPtr;
20337 Jim_Obj *fileNameObj;
20338
20339 if (argc == 4) {
20340 Jim_SubCmdArgError(interp, ct, argv[0]);
20341 return JIM_ERR;
20342 }
20343 if (argc == 5) {
 
20344 if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
20345 return JIM_ERR;
20346 }
20347 resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20348 JimSetSourceInfo(interp, resObjPtr, argv[3], line);
20349 }
20350 else {
20351 if (argv[2]->typePtr == &sourceObjType) {
20352 fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
20353 line = argv[2]->internalRep.sourceValue.lineNumber;
20354 }
20355 else if (argv[2]->typePtr == &scriptObjType) {
20356 ScriptObj *script = JimGetScript(interp, argv[2]);
20357 fileNameObj = script->fileNameObj;
20358 line = script->firstline;
20359 }
20360 else {
20361 fileNameObj = interp->emptyObj;
20362 line = 1;
20363 }
20364 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20365 Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
20366 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
20367 }
20368 Jim_SetResult(interp, resObjPtr);
@@ -23644,11 +23762,13 @@
23644 else {
23645 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
23646 }
23647
23648
 
23649 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
 
23650 #ifdef HAVE_MKSTEMP
23651 fd = mkstemp(filenameObj->bytes);
23652 #else
23653 if (mktemp(filenameObj->bytes) == NULL) {
23654 fd = -1;
@@ -23655,11 +23775,13 @@
23655 }
23656 else {
23657 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
23658 }
23659 #endif
 
23660 umask(mask);
 
23661 if (fd < 0) {
23662 Jim_SetResultErrno(interp, Jim_String(filenameObj));
23663 Jim_FreeNewObj(interp, filenameObj);
23664 return -1;
23665 }
@@ -24258,10 +24380,15 @@
24258 JimPrintErrorMessage(interp);
24259 }
24260
24261 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
24262 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
 
 
 
 
 
24263 retcode = Jim_initjimshInit(interp);
24264
24265 if (argc == 1) {
24266
24267 if (retcode == JIM_ERR) {
24268
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,10 +1,11 @@
1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2 #define JIM_TCL_COMPAT
3 #define JIM_ANSIC
4 #define JIM_REGEXP
5 #define HAVE_NO_AUTOCONF
6 #define JIM_TINY
7 #define _JIMAUTOCONF_H
8 #define TCL_LIBRARY "."
9 #define jim_ext_bootstrap
10 #define jim_ext_aio
11 #define jim_ext_readdir
@@ -60,11 +61,11 @@
61 #define HAVE_UNISTD_H
62 #define HAVE_UMASK
63 #define HAVE_PIPE
64 #define _FILE_OFFSET_BITS 64
65 #endif
66 #define JIM_VERSION 83
67 #ifndef JIM_WIN32COMPAT_H
68 #define JIM_WIN32COMPAT_H
69
70
71
@@ -574,11 +575,11 @@
575
576 typedef struct Jim_Interp {
577 Jim_Obj *result;
578 int unused_errorLine;
579 Jim_Obj *currentFilenameObj;
580 int break_level;
581 int maxCallFrameDepth;
582 int maxEvalDepth;
583 int evalDepth;
584 int returnCode;
585 int returnLevel;
@@ -716,10 +717,18 @@
717 int objc, Jim_Obj *const *objv);
718 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
719 JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
720 JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
721 Jim_Obj **resObjPtrPtr, int flags);
722
723
724 JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
725 int *lineptr);
726
727 JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
728 Jim_Obj *fileNameObj, int lineNumber);
729
730
731
732 JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
733 JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
734 JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
@@ -2343,13 +2352,11 @@
2352 continue;
2353 }
2354 if (JimCheckStreamError(interp, af)) {
2355 return JIM_ERR;
2356 }
2357 break;
 
 
2358 }
2359
2360 return JIM_OK;
2361 }
2362
@@ -2617,18 +2624,13 @@
2624 }
2625
2626 offset = len;
2627 len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
2628 if (len <= 0) {
2629 break;
2630 }
2631 Jim_AppendString(interp, af->readbuf, buf, len);
 
 
 
 
 
2632 }
2633
2634 aio_set_nonblocking(af, nb);
2635
2636 if (!nl && aio_eof(af)) {
@@ -3770,31 +3772,34 @@
3772 int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3773 {
3774 int regcomp_flags = 0;
3775 int regexec_flags = 0;
3776 int opt_all = 0;
3777 int opt_command = 0;
3778 int offset = 0;
3779 regex_t *regex;
3780 const char *p;
3781 int result = JIM_OK;
3782 regmatch_t pmatch[MAX_SUB_MATCHES + 1];
3783 int num_matches = 0;
3784
3785 int i, j, n;
3786 Jim_Obj *varname;
3787 Jim_Obj *resultObj;
3788 Jim_Obj *cmd_prefix = NULL;
3789 Jim_Obj *regcomp_obj = NULL;
3790 const char *source_str;
3791 int source_len;
3792 const char *replace_str = NULL;
3793 int replace_len;
3794 const char *pattern;
3795 int option;
3796 enum {
3797 OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
3798 };
3799 static const char * const options[] = {
3800 "-nocase", "-line", "-all", "-start", "-command", "--", NULL
3801 };
3802
3803 if (argc < 4) {
3804 wrongNumArgs:
3805 Jim_WrongNumArgs(interp, 1, argv,
@@ -3834,24 +3839,43 @@
3839 }
3840 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3841 return JIM_ERR;
3842 }
3843 break;
3844
3845 case OPT_COMMAND:
3846 opt_command = 1;
3847 break;
3848 }
3849 }
3850 if (argc - i != 3 && argc - i != 4) {
3851 goto wrongNumArgs;
3852 }
3853
3854
3855 regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
3856 Jim_IncrRefCount(regcomp_obj);
3857 regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
3858 if (!regex) {
3859 Jim_DecrRefCount(interp, regcomp_obj);
3860 return JIM_ERR;
3861 }
3862 pattern = Jim_String(argv[i]);
3863
3864 source_str = Jim_GetString(argv[i + 1], &source_len);
3865 if (opt_command) {
3866 cmd_prefix = argv[i + 2];
3867 if (Jim_ListLength(interp, cmd_prefix) == 0) {
3868 Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
3869 Jim_DecrRefCount(interp, regcomp_obj);
3870 return JIM_ERR;
3871 }
3872 Jim_IncrRefCount(cmd_prefix);
3873 }
3874 else {
3875 replace_str = Jim_GetString(argv[i + 2], &replace_len);
3876 }
3877 varname = argv[i + 3];
3878
3879
3880 resultObj = Jim_NewStringObj(interp, "", 0);
3881
@@ -3891,39 +3915,62 @@
3915
3916 num_matches++;
3917
3918 Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
3919
3920 if (opt_command) {
3921
3922 Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
3923 for (j = 0; j < MAX_SUB_MATCHES; j++) {
3924 if (pmatch[j].rm_so == -1) {
3925 break;
3926 }
3927 else {
3928 Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3929 Jim_ListAppendElement(interp, cmdListObj, srcObj);
3930 }
3931 }
3932 Jim_IncrRefCount(cmdListObj);
3933
3934 result = Jim_EvalObj(interp, cmdListObj);
3935 Jim_DecrRefCount(interp, cmdListObj);
3936 if (result != JIM_OK) {
3937 goto cmd_error;
3938 }
3939 Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
3940 }
3941 else {
3942
3943 for (j = 0; j < replace_len; j++) {
3944 int idx;
3945 int c = replace_str[j];
3946
3947 if (c == '&') {
3948 idx = 0;
3949 }
3950 else if (c == '\\' && j < replace_len) {
3951 c = replace_str[++j];
3952 if ((c >= '0') && (c <= '9')) {
3953 idx = c - '0';
3954 }
3955 else if ((c == '\\') || (c == '&')) {
3956 Jim_AppendString(interp, resultObj, replace_str + j, 1);
3957 continue;
3958 }
3959 else {
3960 Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
3961 continue;
3962 }
3963 }
3964 else {
3965 Jim_AppendString(interp, resultObj, replace_str + j, 1);
3966 continue;
3967 }
3968 if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
3969 Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
3970 pmatch[idx].rm_eo - pmatch[idx].rm_so);
3971 }
3972 }
3973 }
3974
3975 p += pmatch[0].rm_eo;
3976 n -= pmatch[0].rm_eo;
@@ -3956,25 +4003,37 @@
4003
4004 } while (n);
4005
4006 Jim_AppendString(interp, resultObj, p, -1);
4007
4008 cmd_error:
4009 if (result == JIM_OK) {
4010
4011 if (argc - i == 4) {
4012 result = Jim_SetVariable(interp, varname, resultObj);
4013
4014 if (result == JIM_OK) {
4015 Jim_SetResultInt(interp, num_matches);
4016 }
4017 else {
4018 Jim_FreeObj(interp, resultObj);
4019 }
4020 }
4021 else {
4022 Jim_SetResult(interp, resultObj);
4023 result = JIM_OK;
4024 }
4025 }
4026 else {
4027 Jim_FreeObj(interp, resultObj);
4028 }
4029
4030 if (opt_command) {
4031 Jim_DecrRefCount(interp, cmd_prefix);
4032 }
4033
4034 Jim_DecrRefCount(interp, regcomp_obj);
4035
4036 return result;
4037 }
4038
4039 int Jim_regexpInit(Jim_Interp *interp)
@@ -6353,10 +6412,11 @@
6412 Jim_SetResultString(interp, "Failed to parse time according to format", -1);
6413 return JIM_ERR;
6414 }
6415
6416
6417 tm.tm_isdst = options.gmt ? 0 : -1;
6418 Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
6419
6420 return JIM_OK;
6421 }
6422 #endif
@@ -6732,11 +6792,13 @@
6792 Jim_arrayInit(interp);
6793 Jim_stdlibInit(interp);
6794 Jim_tclcompatInit(interp);
6795 return JIM_OK;
6796 }
6797 #ifndef JIM_TINY
6798 #define JIM_OPTIMIZATION
6799 #endif
6800
6801 #include <stdio.h>
6802 #include <stdlib.h>
6803
6804 #include <string.h>
@@ -6792,11 +6854,13 @@
6854
6855
6856
6857 #define JIM_INTEGER_SPACE 24
6858
6859 #if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
6860 static const char *jim_tt_name(int type);
6861 #endif
6862
6863 #ifdef JIM_DEBUG_PANIC
6864 static void JimPanicDump(int fail_condition, const char *fmt, ...);
6865 #define JimPanic(X) JimPanicDump X
6866 #else
@@ -6828,11 +6892,10 @@
6892 static int JimSign(jim_wide w);
6893 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
6894 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
6895 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
6896 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
 
6897 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
6898
6899 #define JIM_DICT_SUGAR 100
6900
6901
@@ -7807,10 +7870,11 @@
7870 int tt;
7871 int eof;
7872 int inquote;
7873 int comment;
7874 struct JimParseMissing missing;
7875 const char *errmsg;
7876 };
7877
7878 static int JimParseScript(struct JimParserCtx *pc);
7879 static int JimParseSep(struct JimParserCtx *pc);
7880 static int JimParseEol(struct JimParserCtx *pc);
@@ -9507,21 +9571,10 @@
9571 {
9572 dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
9573 Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
9574 }
9575
 
 
 
 
 
 
 
 
 
 
 
9576 static const Jim_ObjType scriptLineObjType = {
9577 "scriptline",
9578 NULL,
9579 NULL,
9580 NULL,
@@ -9578,10 +9631,11 @@
9631 } ScriptObj;
9632
9633 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9634 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
9635 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
9636 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
9637
9638 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9639 {
9640 int i;
9641 struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
@@ -9793,11 +9847,11 @@
9847
9848 token->type = t->type;
9849 token->objPtr = JimMakeScriptObj(interp, t);
9850 Jim_IncrRefCount(token->objPtr);
9851
9852 Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9853 token++;
9854 }
9855 }
9856
9857 if (lineargs == 0) {
@@ -9852,10 +9906,43 @@
9906 }
9907
9908 Jim_SetResultString(interp, msg, -1);
9909 return JIM_ERR;
9910 }
9911
9912 Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
9913 {
9914 int line;
9915 Jim_Obj *fileNameObj;
9916
9917 if (objPtr->typePtr == &sourceObjType) {
9918 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9919 line = objPtr->internalRep.sourceValue.lineNumber;
9920 }
9921 else if (objPtr->typePtr == &scriptObjType) {
9922 ScriptObj *script = JimGetScript(interp, objPtr);
9923 fileNameObj = script->fileNameObj;
9924 line = script->firstline;
9925 }
9926 else {
9927 fileNameObj = interp->emptyObj;
9928 line = 1;
9929 }
9930 *lineptr = line;
9931 return fileNameObj;
9932 }
9933
9934 void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9935 Jim_Obj *fileNameObj, int lineNumber)
9936 {
9937 JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
9938 Jim_FreeIntRep(interp, objPtr);
9939 Jim_IncrRefCount(fileNameObj);
9940 objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9941 objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9942 objPtr->typePtr = &sourceObjType;
9943 }
9944
9945 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9946 ParseTokenList *tokenlist)
9947 {
9948 int i;
@@ -9881,16 +9968,15 @@
9968 int scriptTextLen;
9969 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
9970 struct JimParserCtx parser;
9971 struct ScriptObj *script;
9972 ParseTokenList tokenlist;
9973 Jim_Obj *fileNameObj;
9974 int line;
9975
9976
9977 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
 
 
9978
9979
9980 ScriptTokenListInit(&tokenlist);
9981
9982 JimParserInit(&parser, scriptText, scriptTextLen, line);
@@ -9905,16 +9991,11 @@
9991
9992
9993 script = Jim_Alloc(sizeof(*script));
9994 memset(script, 0, sizeof(*script));
9995 script->inUse = 1;
9996 script->fileNameObj = fileNameObj;
 
 
 
 
 
9997 Jim_IncrRefCount(script->fileNameObj);
9998 script->missing = parser.missing.ch;
9999 script->linenr = parser.missing.line;
10000
10001 ScriptObjAddTokens(interp, script, &tokenlist);
@@ -11386,14 +11467,15 @@
11467 Jim_DecrRefCount(i, i->unknown);
11468 Jim_DecrRefCount(i, i->defer);
11469 Jim_DecrRefCount(i, i->nullScriptObj);
11470 Jim_DecrRefCount(i, i->currentFilenameObj);
11471
11472 Jim_FreeHashTable(&i->commands);
11473
11474
11475 Jim_InterpIncrProcEpoch(i);
11476
 
11477 #ifdef JIM_REFERENCES
11478 Jim_FreeHashTable(&i->references);
11479 #endif
11480 Jim_FreeHashTable(&i->packages);
11481 Jim_Free(i->prngState);
@@ -11588,20 +11670,28 @@
11670 Jim_DecrRefCount(interp, interp->stackTrace);
11671 interp->stackTrace = stackTraceObj;
11672 interp->errorFlag = 1;
11673 }
11674
11675 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
11676 {
11677 if (!interp->errorFlag) {
11678 int i;
11679 Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
11680
11681 if (interp->procLevel == 0 && script) {
11682 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11683 Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
11684 Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
11685 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11686 }
11687 else {
11688 for (i = 0; i <= interp->procLevel; i++) {
11689 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11690 if (frame) {
11691 JimAddStackFrame(interp, frame, stackTrace);
11692 }
11693 }
11694 }
11695 JimSetStackTrace(interp, stackTrace);
11696 }
11697 }
@@ -12288,18 +12378,11 @@
12378 Jim_Free(dict);
12379 return JIM_OK;
12380 }
12381
12382
12383 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
 
 
 
 
 
 
 
12384 Jim_IncrRefCount(fileNameObj);
12385
12386
12387 str = Jim_GetString(objPtr, &strLen);
12388
@@ -12317,11 +12400,11 @@
12400
12401 JimParseList(&parser);
12402 if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
12403 continue;
12404 elementPtr = JimParserGetTokenObj(interp, &parser);
12405 Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12406 ListAppendElement(objPtr, elementPtr);
12407 }
12408 }
12409 Jim_DecrRefCount(interp, fileNameObj);
12410 return JIM_OK;
@@ -12372,11 +12455,12 @@
12455 enum {
12456 JIM_LSORT_ASCII,
12457 JIM_LSORT_NOCASE,
12458 JIM_LSORT_INTEGER,
12459 JIM_LSORT_REAL,
12460 JIM_LSORT_COMMAND,
12461 JIM_LSORT_DICT
12462 } type;
12463 int order;
12464 Jim_Obj **indexv;
12465 int indexc;
12466 int unique;
@@ -12404,10 +12488,47 @@
12488
12489 static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12490 {
12491 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
12492 }
12493
12494 static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12495 {
12496
12497 const char *left = Jim_String(*lhsObj);
12498 const char *right = Jim_String(*rhsObj);
12499
12500 while (1) {
12501 if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
12502
12503 jim_wide lint, rint;
12504 char *lend, *rend;
12505 lint = jim_strtoull(left, &lend);
12506 rint = jim_strtoull(right, &rend);
12507 if (lint != rint) {
12508 return JimSign(lint - rint) * sort_info->order;
12509 }
12510 if (lend -left != rend - right) {
12511 return JimSign((lend - left) - (rend - right)) * sort_info->order;
12512 }
12513 left = lend;
12514 right = rend;
12515 }
12516 else {
12517 int cl, cr;
12518 left += utf8_tounicode_case(left, &cl, 1);
12519 right += utf8_tounicode_case(right, &cr, 1);
12520 if (cl != cr) {
12521 return JimSign(cl - cr) * sort_info->order;
12522 }
12523 if (cl == 0) {
12524
12525 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12526 }
12527 }
12528 }
12529 }
12530
12531 static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12532 {
12533 jim_wide lhs = 0, rhs = 0;
12534
@@ -12519,10 +12640,13 @@
12640 fn = ListSortReal;
12641 break;
12642 case JIM_LSORT_COMMAND:
12643 fn = ListSortCommand;
12644 break;
12645 case JIM_LSORT_DICT:
12646 fn = ListSortDict;
12647 break;
12648 default:
12649 fn = NULL;
12650 JimPanic((1, "ListSort called with invalid sort type"));
12651 return -1;
12652 }
@@ -12567,10 +12691,15 @@
12691 {
12692 int currentLen = listPtr->internalRep.listValue.len;
12693 int requiredLen = currentLen + elemc;
12694 int i;
12695 Jim_Obj **point;
12696
12697 if (elemc == 0) {
12698
12699 return;
12700 }
12701
12702 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
12703 if (currentLen) {
12704
12705 requiredLen *= 2;
@@ -14332,10 +14461,12 @@
14461 #define JIM_EXPR_OPERATORS_NUM \
14462 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
14463
14464 static int JimParseExpression(struct JimParserCtx *pc)
14465 {
14466 pc->errmsg = NULL;
14467
14468 while (1) {
14469
14470 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
14471 if (*pc->p == '\n') {
14472 pc->linenr++;
@@ -14382,10 +14513,11 @@
14513 if (JimParseVar(pc) == JIM_ERR)
14514 return JimParseExprOperator(pc);
14515 else {
14516
14517 if (pc->tt == JIM_TT_EXPRSUGAR) {
14518 pc->errmsg = "nesting expr in expr is not allowed";
14519 return JIM_ERR;
14520 }
14521 return JIM_OK;
14522 }
14523 break;
@@ -14526,10 +14658,11 @@
14658 while (len && isspace(UCHAR(*p))) {
14659 len--;
14660 p++;
14661 }
14662 if (*p != '(') {
14663 pc->errmsg = "function requires parentheses";
14664 return JIM_ERR;
14665 }
14666 }
14667 pc->tend = pc->p + bestLen - 1;
14668 pc->p += bestLen;
@@ -14537,35 +14670,10 @@
14670
14671 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
14672 return JIM_OK;
14673 }
14674
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14675
14676 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14677 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
14678 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
14679
@@ -14867,11 +14975,11 @@
14975 if (!objPtr) {
14976
14977 objPtr = Jim_NewStringObj(interp, t->token, t->len);
14978 if (t->type == JIM_TT_CMD) {
14979
14980 Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
14981 }
14982 }
14983
14984
14985 node = builder->next++;
@@ -14965,18 +15073,11 @@
15073 int line;
15074 Jim_Obj *fileNameObj;
15075 int rc = JIM_ERR;
15076
15077
15078 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
 
 
 
 
 
 
 
15079 Jim_IncrRefCount(fileNameObj);
15080
15081 exprText = Jim_GetString(objPtr, &exprTextLen);
15082
15083
@@ -14985,10 +15086,13 @@
15086 JimParserInit(&parser, exprText, exprTextLen, line);
15087 while (!parser.eof) {
15088 if (JimParseExpression(&parser) != JIM_OK) {
15089 ScriptTokenListFree(&tokenlist);
15090 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
15091 if (parser.errmsg) {
15092 Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
15093 }
15094 expr = NULL;
15095 goto err;
15096 }
15097
15098 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
@@ -15004,14 +15108,21 @@
15108 tokenlist.list[i].len, tokenlist.list[i].token);
15109 }
15110 }
15111 #endif
15112
15113 if (tokenlist.count <= 1) {
15114 Jim_SetResultString(interp, "empty expression", -1);
15115 rc = JIM_ERR;
15116 }
15117 else {
15118 rc = JimParseCheckMissing(interp, parser.missing.ch);
15119 }
15120 if (rc != JIM_OK) {
15121 ScriptTokenListFree(&tokenlist);
15122 Jim_DecrRefCount(interp, fileNameObj);
15123 return rc;
15124 }
15125
15126
15127 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
15128
@@ -15858,17 +15969,22 @@
15969
15970 int ret;
15971 Jim_Obj *nargv[7];
15972 Jim_Obj *traceCmdObj = interp->traceCmdObj;
15973 Jim_Obj *resultObj = Jim_GetResult(interp);
15974 ScriptObj *script = NULL;
15975
15976
15977
15978 if (interp->evalFrame->scriptObj) {
15979 script = JimGetScript(interp, interp->evalFrame->scriptObj);
15980 }
15981
15982 nargv[0] = traceCmdObj;
15983 nargv[1] = Jim_NewStringObj(interp, type, -1);
15984 nargv[2] = script ? script->fileNameObj : interp->emptyObj;
15985 nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
15986 nargv[4] = resultObj;
15987 nargv[5] = argv[0];
15988 nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
15989
15990
@@ -15986,11 +16102,11 @@
16102 else {
16103 interp->cmdPrivData = cmdPtr->u.native.privData;
16104 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
16105 }
16106 if (retcode == JIM_ERR) {
16107 JimSetErrorStack(interp, NULL);
16108 }
16109 }
16110
16111 if (tailcallObj) {
16112
@@ -16021,11 +16137,11 @@
16137
16138 out:
16139 JimDecrCmdRefCount(interp, cmdPtr);
16140
16141 if (retcode == JIM_ERR) {
16142 JimSetErrorStack(interp, NULL);
16143 }
16144
16145 if (interp->framePtr->tailcallObj) {
16146 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
16147 Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
@@ -16042,10 +16158,11 @@
16158 Jim_EvalFrame frame;
16159
16160
16161 for (i = 0; i < objc; i++)
16162 Jim_IncrRefCount(objv[i]);
16163
16164
16165 JimPushEvalFrame(interp, &frame, NULL);
16166
16167 retcode = JimInvokeCommand(interp, objc, objv);
16168
@@ -16181,11 +16298,13 @@
16298 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
16299 Jim_IncrRefCount(intv[2]);
16300 }
16301 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
16302
16303 int line;
16304 Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
16305 Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
16306 }
16307
16308
16309 s = objPtr->bytes = Jim_Alloc(totlen + 1);
16310 objPtr->length = totlen;
@@ -16248,11 +16367,11 @@
16367 }
16368
16369 Jim_IncrRefCount(scriptObjPtr);
16370 script = JimGetScript(interp, scriptObjPtr);
16371 if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16372 JimSetErrorStack(interp, script);
16373 Jim_DecrRefCount(interp, scriptObjPtr);
16374 return JIM_ERR;
16375 }
16376
16377 Jim_SetEmptyResult(interp);
@@ -16420,11 +16539,11 @@
16539 }
16540 }
16541
16542
16543 if (retcode == JIM_ERR) {
16544 JimSetErrorStack(interp, NULL);
16545 }
16546
16547 JimPopEvalFrame(interp);
16548
16549 Jim_FreeIntRep(interp, scriptObjPtr);
@@ -16648,11 +16767,11 @@
16767 Jim_Obj *scriptObjPtr;
16768
16769 scriptObjPtr = Jim_NewStringObj(interp, script, -1);
16770 Jim_IncrRefCount(scriptObjPtr);
16771 if (filename) {
16772 Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16773 }
16774 retval = Jim_EvalObj(interp, scriptObjPtr);
16775 Jim_DecrRefCount(interp, scriptObjPtr);
16776 return retval;
16777 }
@@ -16730,11 +16849,11 @@
16849 if (!scriptObjPtr) {
16850 return JIM_ERR;
16851 }
16852
16853 filenameObj = Jim_NewStringObj(interp, filename, -1);
16854 Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16855
16856 oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
16857
16858 retcode = Jim_EvalObj(interp, scriptObjPtr);
16859
@@ -16771,11 +16890,13 @@
16890 if (JimParseVar(pc) == JIM_OK) {
16891 return;
16892 }
16893
16894 pc->tstart = pc->p;
16895
16896 pc->p++;
16897 pc->len--;
16898 }
16899 while (pc->len) {
16900 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16901 break;
16902 }
@@ -17274,11 +17395,11 @@
17395 }
17396
17397 static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
17398 {
17399 if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17400 if (--interp->break_level > 0) {
17401 return 1;
17402 }
17403 }
17404 return 0;
17405 }
@@ -17464,19 +17585,18 @@
17585 #endif
17586
17587 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
17588
17589 retval = Jim_EvalObj(interp, argv[4]);
17590 if (JimCheckLoopRetcode(interp, retval)) {
17591 immediate++;
17592 break;
17593 }
17594 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17595
17596 JIM_IF_OPTIM(evalnext:)
17597 retval = Jim_EvalObj(interp, argv[3]);
 
 
 
 
17598 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17599
17600 JIM_IF_OPTIM(testcond:)
17601 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17602 }
@@ -18327,21 +18447,23 @@
18447
18448 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
18449 {
18450 static const char * const options[] = {
18451 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18452 "-stride", "-dictionary", NULL
18453 };
18454 enum {
18455 OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18456 OPT_STRIDE, OPT_DICT
18457 };
18458 Jim_Obj *resObj;
18459 int i;
18460 int retCode;
18461 int shared;
18462 long stride = 1;
18463 Jim_Obj **elements;
18464 int listlen;
18465
18466 struct lsort_info info;
18467
18468 if (argc < 2) {
18469 wrongargs:
@@ -18364,10 +18486,13 @@
18486 return JIM_ERR;
18487 switch (option) {
18488 case OPT_ASCII:
18489 info.type = JIM_LSORT_ASCII;
18490 break;
18491 case OPT_DICT:
18492 info.type = JIM_LSORT_DICT;
18493 break;
18494 case OPT_NOCASE:
18495 info.type = JIM_LSORT_NOCASE;
18496 break;
18497 case OPT_INTEGER:
18498 info.type = JIM_LSORT_INTEGER;
@@ -18418,17 +18543,21 @@
18543 i++;
18544 break;
18545 }
18546 }
18547 resObj = argv[argc - 1];
18548 JimListGetElements(interp, resObj, &listlen, &elements);
18549 if (listlen <= 1) {
18550
18551 Jim_SetResult(interp, resObj);
18552 return JIM_OK;
18553 }
18554
18555 if (stride > 1) {
18556 Jim_Obj *tmpListObj;
 
 
18557 int i;
18558
 
18559 if (listlen % stride) {
18560 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18561 return JIM_ERR;
18562 }
18563
@@ -18612,11 +18741,11 @@
18741 long level;
18742 int ret = Jim_GetLong(interp, argv[1], &level);
18743 if (ret != JIM_OK) {
18744 return ret;
18745 }
18746 interp->break_level = level;
18747 }
18748 return retcode;
18749 }
18750
18751
@@ -20330,39 +20459,28 @@
20459 }
20460 Jim_SetResult(interp, interp->currentFilenameObj);
20461 return JIM_OK;
20462
20463 case INFO_SOURCE:{
 
20464 Jim_Obj *resObjPtr;
20465 Jim_Obj *fileNameObj;
20466
20467 if (argc == 4) {
20468 Jim_SubCmdArgError(interp, ct, argv[0]);
20469 return JIM_ERR;
20470 }
20471 if (argc == 5) {
20472 jim_wide line;
20473 if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
20474 return JIM_ERR;
20475 }
20476 resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20477 Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
20478 }
20479 else {
20480 int line;
20481 fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
 
 
 
 
 
 
 
 
 
 
 
20482 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20483 Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
20484 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
20485 }
20486 Jim_SetResult(interp, resObjPtr);
@@ -23644,11 +23762,13 @@
23762 else {
23763 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
23764 }
23765
23766
23767 #ifdef HAVE_UMASK
23768 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
23769 #endif
23770 #ifdef HAVE_MKSTEMP
23771 fd = mkstemp(filenameObj->bytes);
23772 #else
23773 if (mktemp(filenameObj->bytes) == NULL) {
23774 fd = -1;
@@ -23655,11 +23775,13 @@
23775 }
23776 else {
23777 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
23778 }
23779 #endif
23780 #ifdef HAVE_UMASK
23781 umask(mask);
23782 #endif
23783 if (fd < 0) {
23784 Jim_SetResultErrno(interp, Jim_String(filenameObj));
23785 Jim_FreeNewObj(interp, filenameObj);
23786 return -1;
23787 }
@@ -24258,10 +24380,15 @@
24380 JimPrintErrorMessage(interp);
24381 }
24382
24383 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
24384 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
24385 #ifdef USE_LINENOISE
24386 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
24387 #else
24388 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
24389 #endif
24390 retcode = Jim_initjimshInit(interp);
24391
24392 if (argc == 1) {
24393
24394 if (retcode == JIM_ERR) {
24395
--- extsrc/cson_amalgamation.c
+++ extsrc/cson_amalgamation.c
@@ -1435,11 +1435,10 @@
14351435
#if defined(__cplusplus)
14361436
extern "C" {
14371437
#endif
14381438
14391439
1440
-
14411440
/**
14421441
This type holds the "vtbl" for type-specific operations when
14431442
working with cson_value objects.
14441443
14451444
All cson_values of a given logical type share a pointer to a single
@@ -1686,12 +1685,12 @@
16861685
: 0;
16871686
}
16881687
16891688
char const * cson_rc_string(int rc)
16901689
{
1691
- if(0 == rc) return "OK";
1692
-#define CHECK(N) else if(cson_rc.N == rc ) return #N
1690
+ switch(rc){
1691
+#define CHECK(N) case CSON_RC_##N: return #N;
16931692
CHECK(OK);
16941693
CHECK(ArgError);
16951694
CHECK(RangeError);
16961695
CHECK(TypeError);
16971696
CHECK(IOError);
@@ -1708,11 +1707,12 @@
17081707
CHECK(Parse_INVALID_NUMBER);
17091708
CHECK(Parse_NESTING_DEPTH_REACHED);
17101709
CHECK(Parse_UNBALANCED_COLLECTION);
17111710
CHECK(Parse_EXPECTED_KEY);
17121711
CHECK(Parse_EXPECTED_COLON);
1713
- else return "UnknownError";
1712
+ default: return "UnknownError";
1713
+ }
17141714
#undef CHECK
17151715
}
17161716
17171717
/**
17181718
If CSON_LOG_ALLOC is true then the cson_malloc/realloc/free() routines
@@ -1854,11 +1854,11 @@
18541854
}
18551855
18561856
#if 0
18571857
int cson_value_refcount_set( cson_value * cv, unsigned short rc )
18581858
{
1859
- if( NULL == cv ) return cson_rc.ArgError;
1859
+ if( NULL == cv ) return CSON_RC_ArgError;
18601860
else
18611861
{
18621862
cv->refcount = rc;
18631863
return 0;
18641864
}
@@ -1865,14 +1865,14 @@
18651865
}
18661866
#endif
18671867
18681868
int cson_value_add_reference( cson_value * cv )
18691869
{
1870
- if( NULL == cv ) return cson_rc.ArgError;
1870
+ if( NULL == cv ) return CSON_RC_ArgError;
18711871
else if( (cv->refcount+1) < cv->refcount )
18721872
{
1873
- return cson_rc.RangeError;
1873
+ return CSON_RC_RangeError;
18741874
}
18751875
else
18761876
{
18771877
cson_refcount_incr( cv );
18781878
return 0;
@@ -2335,11 +2335,11 @@
23352335
val->refcount = rc;
23362336
}
23372337
}
23382338
}
23392339
2340
-static cson_value * cson_value_array_alloc()
2340
+static cson_value * cson_value_array_alloc(void)
23412341
{
23422342
cson_value * v = cson_value_new(CSON_TYPE_ARRAY,0);
23432343
if( NULL != v )
23442344
{
23452345
cson_array * ar = CSON_ARRAY(v);
@@ -2347,11 +2347,11 @@
23472347
*ar = cson_array_empty;
23482348
}
23492349
return v;
23502350
}
23512351
2352
-static cson_value * cson_value_object_alloc()
2352
+static cson_value * cson_value_object_alloc(void)
23532353
{
23542354
cson_value * v = cson_value_new(CSON_TYPE_OBJECT,0);
23552355
if( NULL != v )
23562356
{
23572357
cson_object * obj = CSON_OBJ(v);
@@ -2359,28 +2359,28 @@
23592359
*obj = cson_object_empty;
23602360
}
23612361
return v;
23622362
}
23632363
2364
-cson_value * cson_value_new_object()
2364
+cson_value * cson_value_new_object(void)
23652365
{
23662366
return cson_value_object_alloc();
23672367
}
23682368
2369
-cson_object * cson_new_object()
2369
+cson_object * cson_new_object(void)
23702370
{
23712371
23722372
return cson_value_get_object( cson_value_new_object() );
23732373
}
23742374
2375
-cson_value * cson_value_new_array()
2375
+cson_value * cson_value_new_array(void)
23762376
{
23772377
return cson_value_array_alloc();
23782378
}
23792379
23802380
2381
-cson_array * cson_new_array()
2381
+cson_array * cson_new_array(void)
23822382
{
23832383
return cson_value_get_array( cson_value_new_array() );
23842384
}
23852385
23862386
/**
@@ -2502,11 +2502,11 @@
25022502
int rc;
25032503
enum { BufSize = 1024 * 4 };
25042504
char rbuf[BufSize];
25052505
size_t total = 0;
25062506
unsigned int rlen = 0;
2507
- if( ! dest || ! src ) return cson_rc.ArgError;
2507
+ if( ! dest || ! src ) return CSON_RC_ArgError;
25082508
dest->used = 0;
25092509
while(1)
25102510
{
25112511
rlen = BufSize;
25122512
rc = src( state, rbuf, &rlen );
@@ -2530,16 +2530,16 @@
25302530
}
25312531
25322532
int cson_data_source_FILE( void * state, void * dest, unsigned int * n )
25332533
{
25342534
FILE * f = (FILE*) state;
2535
- if( ! state || ! n || !dest ) return cson_rc.ArgError;
2536
- else if( !*n ) return cson_rc.RangeError;
2535
+ if( ! state || ! n || !dest ) return CSON_RC_ArgError;
2536
+ else if( !*n ) return CSON_RC_RangeError;
25372537
*n = (unsigned int)fread( dest, 1, *n, f );
25382538
if( !*n )
25392539
{
2540
- return feof(f) ? 0 : cson_rc.IOError;
2540
+ return feof(f) ? 0 : CSON_RC_IOError;
25412541
}
25422542
return 0;
25432543
}
25442544
25452545
int cson_parse_FILE( cson_value ** tgt, FILE * src,
@@ -2553,11 +2553,11 @@
25532553
{
25542554
/**
25552555
FIXME: move the to-bool operation into cson_value_api, like we
25562556
do in the C++ API.
25572557
*/
2558
- if( ! val || !val->api ) return cson_rc.ArgError;
2558
+ if( ! val || !val->api ) return CSON_RC_ArgError;
25592559
else
25602560
{
25612561
int rc = 0;
25622562
char b = 0;
25632563
switch( val->api->typeID )
@@ -2588,11 +2588,11 @@
25882588
cson_value_fetch_double( val, &d );
25892589
b = (0.0==d) ? 0 : 1;
25902590
break;
25912591
}
25922592
default:
2593
- rc = cson_rc.TypeError;
2593
+ rc = CSON_RC_TypeError;
25942594
break;
25952595
}
25962596
if( v ) *v = b;
25972597
return rc;
25982598
}
@@ -2605,11 +2605,11 @@
26052605
return i;
26062606
}
26072607
26082608
int cson_value_fetch_integer( cson_value const * val, cson_int_t * v )
26092609
{
2610
- if( ! val || !val->api ) return cson_rc.ArgError;
2610
+ if( ! val || !val->api ) return CSON_RC_ArgError;
26112611
else
26122612
{
26132613
cson_int_t i = 0;
26142614
int rc = 0;
26152615
switch(val->api->typeID)
@@ -2641,11 +2641,11 @@
26412641
}
26422642
case CSON_TYPE_STRING:
26432643
case CSON_TYPE_ARRAY:
26442644
case CSON_TYPE_OBJECT:
26452645
default:
2646
- rc = cson_rc.TypeError;
2646
+ rc = CSON_RC_TypeError;
26472647
break;
26482648
}
26492649
if(!rc && v) *v = i;
26502650
return rc;
26512651
}
@@ -2658,11 +2658,11 @@
26582658
return i;
26592659
}
26602660
26612661
int cson_value_fetch_double( cson_value const * val, cson_double_t * v )
26622662
{
2663
- if( ! val || !val->api ) return cson_rc.ArgError;
2663
+ if( ! val || !val->api ) return CSON_RC_ArgError;
26642664
else
26652665
{
26662666
cson_double_t d = 0.0;
26672667
int rc = 0;
26682668
switch(val->api->typeID)
@@ -2687,11 +2687,11 @@
26872687
cson_double_t const* dv = CSON_DBL(val);
26882688
d = dv ? *dv : 0.0;
26892689
break;
26902690
}
26912691
default:
2692
- rc = cson_rc.TypeError;
2692
+ rc = CSON_RC_TypeError;
26932693
break;
26942694
}
26952695
if(v) *v = d;
26962696
return rc;
26972697
}
@@ -2704,12 +2704,12 @@
27042704
return i;
27052705
}
27062706
27072707
int cson_value_fetch_string( cson_value const * val, cson_string ** dest )
27082708
{
2709
- if( ! val || ! dest ) return cson_rc.ArgError;
2710
- else if( ! cson_value_is_string(val) ) return cson_rc.TypeError;
2709
+ if( ! val || ! dest ) return CSON_RC_ArgError;
2710
+ else if( ! cson_value_is_string(val) ) return CSON_RC_TypeError;
27112711
else
27122712
{
27132713
if( dest ) *dest = CSON_STR(val);
27142714
return 0;
27152715
}
@@ -2727,12 +2727,12 @@
27272727
return cson_string_cstr( cson_value_get_string(val) );
27282728
}
27292729
27302730
int cson_value_fetch_object( cson_value const * val, cson_object ** obj )
27312731
{
2732
- if( ! val ) return cson_rc.ArgError;
2733
- else if( ! cson_value_is_object(val) ) return cson_rc.TypeError;
2732
+ if( ! val ) return CSON_RC_ArgError;
2733
+ else if( ! cson_value_is_object(val) ) return CSON_RC_TypeError;
27342734
else
27352735
{
27362736
if(obj) *obj = CSON_OBJ(val);
27372737
return 0;
27382738
}
@@ -2744,12 +2744,12 @@
27442744
return obj;
27452745
}
27462746
27472747
int cson_value_fetch_array( cson_value const * val, cson_array ** ar)
27482748
{
2749
- if( ! val ) return cson_rc.ArgError;
2750
- else if( !cson_value_is_array(val) ) return cson_rc.TypeError;
2749
+ if( ! val ) return CSON_RC_ArgError;
2750
+ else if( !cson_value_is_array(val) ) return CSON_RC_TypeError;
27512751
else
27522752
{
27532753
if(ar) *ar = CSON_ARRAY(val);
27542754
return 0;
27552755
}
@@ -2760,11 +2760,11 @@
27602760
cson_array * ar = NULL;
27612761
cson_value_fetch_array( v, &ar );
27622762
return ar;
27632763
}
27642764
2765
-cson_kvp * cson_kvp_alloc()
2765
+cson_kvp * cson_kvp_alloc(void)
27662766
{
27672767
cson_kvp * kvp = (cson_kvp*)cson_malloc(sizeof(cson_kvp),"cson_kvp");
27682768
if( kvp )
27692769
{
27702770
*kvp = cson_kvp_empty;
@@ -2774,20 +2774,20 @@
27742774
27752775
27762776
27772777
int cson_array_append( cson_array * ar, cson_value * v )
27782778
{
2779
- if( !ar || !v ) return cson_rc.ArgError;
2780
- else if( (ar->list.count+1) < ar->list.count ) return cson_rc.RangeError;
2779
+ if( !ar || !v ) return CSON_RC_ArgError;
2780
+ else if( (ar->list.count+1) < ar->list.count ) return CSON_RC_RangeError;
27812781
else
27822782
{
27832783
if( !ar->list.alloced || (ar->list.count == ar->list.alloced-1))
27842784
{
27852785
unsigned int const n = ar->list.count ? (ar->list.count*2) : 7;
27862786
if( n > cson_value_list_reserve( &ar->list, n ) )
27872787
{
2788
- return cson_rc.AllocError;
2788
+ return CSON_RC_AllocError;
27892789
}
27902790
}
27912791
return cson_array_set( ar, ar->list.count, v );
27922792
}
27932793
}
@@ -2832,20 +2832,20 @@
28322832
cson_value * cson_value_new_bool( char v )
28332833
{
28342834
return v ? &CSON_SPECIAL_VALUES[CSON_VAL_TRUE] : &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
28352835
}
28362836
2837
-cson_value * cson_value_true()
2837
+cson_value * cson_value_true(void)
28382838
{
28392839
return &CSON_SPECIAL_VALUES[CSON_VAL_TRUE];
28402840
}
2841
-cson_value * cson_value_false()
2841
+cson_value * cson_value_false(void)
28422842
{
28432843
return &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
28442844
}
28452845
2846
-cson_value * cson_value_null()
2846
+cson_value * cson_value_null(void)
28472847
{
28482848
return &CSON_SPECIAL_VALUES[CSON_VAL_NULL];
28492849
}
28502850
28512851
cson_value * cson_new_int( cson_int_t v )
@@ -2917,12 +2917,12 @@
29172917
return cson_string_value( cson_new_string(str, len) );
29182918
}
29192919
29202920
int cson_array_value_fetch( cson_array const * ar, unsigned int pos, cson_value ** v )
29212921
{
2922
- if( !ar) return cson_rc.ArgError;
2923
- if( pos >= ar->list.count ) return cson_rc.RangeError;
2922
+ if( !ar) return CSON_RC_ArgError;
2923
+ if( pos >= ar->list.count ) return CSON_RC_RangeError;
29242924
else
29252925
{
29262926
if(v) *v = ar->list.list[pos];
29272927
return 0;
29282928
}
@@ -2935,11 +2935,11 @@
29352935
return v;
29362936
}
29372937
29382938
int cson_array_length_fetch( cson_array const * ar, unsigned int * v )
29392939
{
2940
- if( ! ar || !v ) return cson_rc.ArgError;
2940
+ if( ! ar || !v ) return CSON_RC_ArgError;
29412941
else
29422942
{
29432943
if(v) *v = ar->list.count;
29442944
return 0;
29452945
}
@@ -2952,11 +2952,11 @@
29522952
return i;
29532953
}
29542954
29552955
int cson_array_reserve( cson_array * ar, unsigned int size )
29562956
{
2957
- if( ! ar ) return cson_rc.ArgError;
2957
+ if( ! ar ) return CSON_RC_ArgError;
29582958
else if( size <= ar->list.alloced )
29592959
{
29602960
/* We don't want to introduce a can of worms by trying to
29612961
handle the cleanup from here.
29622962
*/
@@ -2963,24 +2963,24 @@
29632963
return 0;
29642964
}
29652965
else
29662966
{
29672967
return (ar->list.alloced > cson_value_list_reserve( &ar->list, size ))
2968
- ? cson_rc.AllocError
2968
+ ? CSON_RC_AllocError
29692969
: 0
29702970
;
29712971
}
29722972
}
29732973
29742974
int cson_array_set( cson_array * ar, unsigned int ndx, cson_value * v )
29752975
{
2976
- if( !ar || !v ) return cson_rc.ArgError;
2977
- else if( (ndx+1) < ndx) /* overflow */return cson_rc.RangeError;
2976
+ if( !ar || !v ) return CSON_RC_ArgError;
2977
+ else if( (ndx+1) < ndx) /* overflow */return CSON_RC_RangeError;
29782978
else
29792979
{
29802980
unsigned const int len = cson_value_list_reserve( &ar->list, ndx+1 );
2981
- if( len <= ndx ) return cson_rc.AllocError;
2981
+ if( len <= ndx ) return CSON_RC_AllocError;
29822982
else
29832983
{
29842984
cson_value * old = ar->list.list[ndx];
29852985
if( old )
29862986
{
@@ -3076,18 +3076,18 @@
30763076
}
30773077
#endif
30783078
30793079
int cson_object_unset( cson_object * obj, char const * key )
30803080
{
3081
- if( ! obj || !key || !*key ) return cson_rc.ArgError;
3081
+ if( ! obj || !key || !*key ) return CSON_RC_ArgError;
30823082
else
30833083
{
30843084
unsigned int ndx = 0;
30853085
cson_kvp * kvp = cson_object_search_impl( obj, key, &ndx );
30863086
if( ! kvp )
30873087
{
3088
- return cson_rc.NotFoundError;
3088
+ return CSON_RC_NotFoundError;
30893089
}
30903090
assert( obj->kvp.count > 0 );
30913091
assert( obj->kvp.list[ndx] == kvp );
30923092
cson_kvp_free( kvp );
30933093
obj->kvp.list[ndx] = NULL;
@@ -3109,21 +3109,21 @@
31093109
}
31103110
}
31113111
31123112
int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v )
31133113
{
3114
- if( !obj || !key ) return cson_rc.ArgError;
3114
+ if( !obj || !key ) return CSON_RC_ArgError;
31153115
else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) );
31163116
else
31173117
{
31183118
char const * cKey;
31193119
cson_value * vKey;
31203120
cson_kvp * kvp;
31213121
vKey = cson_string_value(key);
31223122
assert(vKey && (key==CSON_STR(vKey)));
31233123
if( vKey == CSON_VCAST(obj) ){
3124
- return cson_rc.ArgError;
3124
+ return CSON_RC_ArgError;
31253125
}
31263126
cKey = cson_string_cstr(key);
31273127
kvp = cson_object_search_impl( obj, cKey, NULL );
31283128
if( kvp )
31293129
{ /* "I told 'em we've already got one!" */
@@ -3142,19 +3142,19 @@
31423142
if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
31433143
{ /* reserve space */
31443144
unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
31453145
if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
31463146
{
3147
- return cson_rc.AllocError;
3147
+ return CSON_RC_AllocError;
31483148
}
31493149
}
31503150
{ /* insert new item... */
31513151
int rc = 0;
31523152
kvp = cson_kvp_alloc();
31533153
if( ! kvp )
31543154
{
3155
- return cson_rc.AllocError;
3155
+ return CSON_RC_AllocError;
31563156
}
31573157
rc = cson_kvp_list_append( &obj->kvp, kvp );
31583158
if( 0 != rc )
31593159
{
31603160
cson_kvp_free(kvp);
@@ -3174,19 +3174,19 @@
31743174
}
31753175
31763176
}
31773177
int cson_object_set( cson_object * obj, char const * key, cson_value * v )
31783178
{
3179
- if( ! obj || !key || !*key ) return cson_rc.ArgError;
3179
+ if( ! obj || !key || !*key ) return CSON_RC_ArgError;
31803180
else if( NULL == v )
31813181
{
31823182
return cson_object_unset( obj, key );
31833183
}
31843184
else
31853185
{
31863186
cson_string * cs = cson_new_string(key,strlen(key));
3187
- if(!cs) return cson_rc.AllocError;
3187
+ if(!cs) return CSON_RC_AllocError;
31883188
else
31893189
{
31903190
int const rc = cson_object_set_s(obj, cs, v);
31913191
if(rc) cson_value_free(cson_string_value(cs));
31923192
return rc;
@@ -3237,13 +3237,13 @@
32373237
}
32383238
}
32393239
/** @internal
32403240
32413241
If p->node is-a Object then value is inserted into the object
3242
- using p->key. In any other case cson_rc.InternalError is returned.
3242
+ using p->key. In any other case CSON_RC_InternalError is returned.
32433243
3244
- Returns cson_rc.AllocError if an allocation fails.
3244
+ Returns CSON_RC_AllocError if an allocation fails.
32453245
32463246
Returns 0 on success. On error, parsing must be ceased immediately.
32473247
32483248
Ownership of val is ALWAYS TRANSFERED to this function. If this
32493249
function fails, val will be cleaned up and destroyed. (This
@@ -3267,18 +3267,18 @@
32673267
if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
32683268
{
32693269
if( obj->kvp.alloced > cson_kvp_list_reserve( &obj->kvp, obj->kvp.count ? (obj->kvp.count*2) : 5 ) )
32703270
{
32713271
cson_value_free(val);
3272
- return cson_rc.AllocError;
3272
+ return CSON_RC_AllocError;
32733273
}
32743274
}
32753275
kvp = cson_kvp_alloc();
32763276
if( ! kvp )
32773277
{
32783278
cson_value_free(val);
3279
- return cson_rc.AllocError;
3279
+ return CSON_RC_AllocError;
32803280
}
32813281
kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
32823282
assert(0 == kvp->key->refcount);
32833283
cson_refcount_incr(kvp->key);
32843284
p->ckey = NULL;
@@ -3296,11 +3296,11 @@
32963296
return rc;
32973297
}
32983298
else
32993299
{
33003300
if(val) cson_value_free(val);
3301
- return p->errNo = cson_rc.InternalError;
3301
+ return p->errNo = CSON_RC_InternalError;
33023302
}
33033303
33043304
}
33053305
33063306
/** @internal
@@ -3337,11 +3337,11 @@
33373337
return rc;
33383338
}
33393339
else
33403340
{ /* WTF? */
33413341
assert( 0 && "Internal error in cson_parser code" );
3342
- return p->errNo = cson_rc.InternalError;
3342
+ return p->errNo = CSON_RC_InternalError;
33433343
}
33443344
}
33453345
33463346
/**
33473347
Callback for JSON_parser API. Reminder: it returns 0 (meaning false)
@@ -3349,20 +3349,20 @@
33493349
*/
33503350
static int cson_parse_callback( void * cx, int type, JSON_value const * value )
33513351
{
33523352
cson_parser * p = (cson_parser *)cx;
33533353
int rc = 0;
3354
-#define ALLOC_V(T,V) cson_value * v = cson_value_new_##T(V); if( ! v ) { rc = cson_rc.AllocError; break; }
3354
+#define ALLOC_V(T,V) cson_value * v = cson_value_new_##T(V); if( ! v ) { rc = CSON_RC_AllocError; break; }
33553355
switch(type) {
33563356
case JSON_T_ARRAY_BEGIN:
33573357
case JSON_T_OBJECT_BEGIN: {
33583358
cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
33593359
? cson_value_new_array()
33603360
: cson_value_new_object();
33613361
if( ! obja )
33623362
{
3363
- p->errNo = cson_rc.AllocError;
3363
+ p->errNo = CSON_RC_AllocError;
33643364
break;
33653365
}
33663366
if( 0 != rc ) break;
33673367
if( ! p->root )
33683368
{
@@ -3395,11 +3395,11 @@
33953395
}
33963396
case JSON_T_ARRAY_END:
33973397
case JSON_T_OBJECT_END: {
33983398
if( 0 == p->stack.list.count )
33993399
{
3400
- rc = cson_rc.RangeError;
3400
+ rc = CSON_RC_RangeError;
34013401
break;
34023402
}
34033403
#if CSON_OBJECT_PROPS_SORT
34043404
if( cson_value_is_object(p->node) )
34053405
{/* kludge: the parser uses custom cson_object property
@@ -3481,26 +3481,26 @@
34813481
case JSON_T_KEY: {
34823482
assert(!p->ckey);
34833483
p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length );
34843484
if( ! p->ckey )
34853485
{
3486
- rc = cson_rc.AllocError;
3486
+ rc = CSON_RC_AllocError;
34873487
break;
34883488
}
34893489
++p->totalKeyCount;
34903490
break;
34913491
}
34923492
case JSON_T_STRING: {
34933493
cson_value * v = cson_value_new_string( value->vu.str.value, value->vu.str.length );
34943494
rc = ( NULL == v )
3495
- ? cson_rc.AllocError
3495
+ ? CSON_RC_AllocError
34963496
: cson_parser_push_value( p, v );
34973497
break;
34983498
}
34993499
default:
35003500
assert(0);
3501
- rc = cson_rc.InternalError;
3501
+ rc = CSON_RC_InternalError;
35023502
break;
35033503
}
35043504
#undef ALLOC_V
35053505
return ((p->errNo = rc)) ? 0 : 1;
35063506
}
@@ -3512,22 +3512,22 @@
35123512
static int cson_json_err_to_rc( JSON_error jrc )
35133513
{
35143514
switch(jrc)
35153515
{
35163516
case JSON_E_NONE: return 0;
3517
- case JSON_E_INVALID_CHAR: return cson_rc.Parse_INVALID_CHAR;
3518
- case JSON_E_INVALID_KEYWORD: return cson_rc.Parse_INVALID_KEYWORD;
3519
- case JSON_E_INVALID_ESCAPE_SEQUENCE: return cson_rc.Parse_INVALID_ESCAPE_SEQUENCE;
3520
- case JSON_E_INVALID_UNICODE_SEQUENCE: return cson_rc.Parse_INVALID_UNICODE_SEQUENCE;
3521
- case JSON_E_INVALID_NUMBER: return cson_rc.Parse_INVALID_NUMBER;
3522
- case JSON_E_NESTING_DEPTH_REACHED: return cson_rc.Parse_NESTING_DEPTH_REACHED;
3523
- case JSON_E_UNBALANCED_COLLECTION: return cson_rc.Parse_UNBALANCED_COLLECTION;
3524
- case JSON_E_EXPECTED_KEY: return cson_rc.Parse_EXPECTED_KEY;
3525
- case JSON_E_EXPECTED_COLON: return cson_rc.Parse_EXPECTED_COLON;
3526
- case JSON_E_OUT_OF_MEMORY: return cson_rc.AllocError;
3517
+ case JSON_E_INVALID_CHAR: return CSON_RC_Parse_INVALID_CHAR;
3518
+ case JSON_E_INVALID_KEYWORD: return CSON_RC_Parse_INVALID_KEYWORD;
3519
+ case JSON_E_INVALID_ESCAPE_SEQUENCE: return CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE;
3520
+ case JSON_E_INVALID_UNICODE_SEQUENCE: return CSON_RC_Parse_INVALID_UNICODE_SEQUENCE;
3521
+ case JSON_E_INVALID_NUMBER: return CSON_RC_Parse_INVALID_NUMBER;
3522
+ case JSON_E_NESTING_DEPTH_REACHED: return CSON_RC_Parse_NESTING_DEPTH_REACHED;
3523
+ case JSON_E_UNBALANCED_COLLECTION: return CSON_RC_Parse_UNBALANCED_COLLECTION;
3524
+ case JSON_E_EXPECTED_KEY: return CSON_RC_Parse_EXPECTED_KEY;
3525
+ case JSON_E_EXPECTED_COLON: return CSON_RC_Parse_EXPECTED_COLON;
3526
+ case JSON_E_OUT_OF_MEMORY: return CSON_RC_AllocError;
35273527
default:
3528
- return cson_rc.InternalError;
3528
+ return CSON_RC_InternalError;
35293529
}
35303530
}
35313531
35323532
/** @internal
35333533
@@ -3543,11 +3543,11 @@
35433543
any other items inserted into it (or under it) during the parsing
35443544
process.
35453545
*/
35463546
static int cson_parser_clean( cson_parser * p )
35473547
{
3548
- if( ! p ) return cson_rc.ArgError;
3548
+ if( ! p ) return CSON_RC_ArgError;
35493549
else
35503550
{
35513551
if( p->p )
35523552
{
35533553
delete_JSON_parser(p->p);
@@ -3574,11 +3574,11 @@
35743574
cson_parse_opt const opt = opt_ ? *opt_ : cson_parse_opt_empty;
35753575
int rc = 0;
35763576
unsigned int len = 1;
35773577
cson_parse_info info = info_ ? *info_ : cson_parse_info_empty;
35783578
cson_parser p = cson_parser_empty;
3579
- if( ! tgt || ! src ) return cson_rc.ArgError;
3579
+ if( ! tgt || ! src ) return CSON_RC_ArgError;
35803580
35813581
{
35823582
JSON_config jopt = {0};
35833583
init_JSON_config( &jopt );
35843584
jopt.allow_comments = opt.allowComments;
@@ -3587,11 +3587,11 @@
35873587
jopt.handle_floats_manually = 0;
35883588
jopt.callback = cson_parse_callback;
35893589
p.p = new_JSON_parser(&jopt);
35903590
if( ! p.p )
35913591
{
3592
- return cson_rc.AllocError;
3592
+ return CSON_RC_AllocError;
35933593
}
35943594
}
35953595
35963596
do
35973597
{ /* FIXME: buffer the input in multi-kb chunks. */
@@ -3608,11 +3608,11 @@
36083608
}
36093609
if( ! JSON_parser_char(p.p, ch[0]) )
36103610
{
36113611
rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
36123612
if(0==rc) rc = p.errNo;
3613
- if(0==rc) rc = cson_rc.InternalError;
3613
+ if(0==rc) rc = CSON_RC_InternalError;
36143614
info.errorCode = rc;
36153615
break;
36163616
}
36173617
if( '\n' != ch[0]) ++info.col;
36183618
} while(1);
@@ -3630,11 +3630,11 @@
36303630
if( ! JSON_parser_done(p.p) )
36313631
{
36323632
rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
36333633
cson_parser_clean(&p);
36343634
if(0==rc) rc = p.errNo;
3635
- if(0==rc) rc = cson_rc.InternalError;
3635
+ if(0==rc) rc = CSON_RC_InternalError;
36363636
}
36373637
else
36383638
{
36393639
cson_value * root = p.root;
36403640
p.root = NULL;
@@ -3652,11 +3652,11 @@
36523652
*/;
36533653
*tgt = root;
36543654
}
36553655
else
36563656
{ /* then can happen on empty input. */
3657
- rc = cson_rc.UnknownError;
3657
+ rc = CSON_RC_UnknownError;
36583658
}
36593659
}
36603660
return rc;
36613661
}
36623662
@@ -3771,11 +3771,11 @@
37713771
*/
37723772
static int cson_str_to_json( char const * str, unsigned int len,
37733773
char escapeFwdSlash,
37743774
cson_data_dest_f f, void * state )
37753775
{
3776
- if( NULL == f ) return cson_rc.ArgError;
3776
+ if( NULL == f ) return CSON_RC_ArgError;
37773777
else if( !str || !*str || (0 == len) )
37783778
{ /* special case for 0-length strings. */
37793779
return f( state, "\"\"", 2 );
37803780
}
37813781
else
@@ -3877,26 +3877,26 @@
38773877
#if defined(CSON_FOSSIL_MODE)
38783878
assume_latin1:
38793879
#endif
38803880
memset(ubuf,0,UBLen);
38813881
if(ch <= 0xFFFF){
3882
- rc = sprintf(ubuf, "\\u%04x",ch);
3882
+ rc = snprintf(ubuf, (size_t)UBLen, "\\u%04x",ch);
38833883
if( rc != 6 )
38843884
{
3885
- rc = cson_rc.RangeError;
3885
+ rc = CSON_RC_RangeError;
38863886
break;
38873887
}
38883888
rc = f( state, ubuf, 6 );
38893889
}else{ /* encode as a UTF16 surrogate pair */
38903890
/* http://unicodebook.readthedocs.org/en/latest/unicode_encodings.html#surrogates */
38913891
ch -= 0x10000;
3892
- rc = sprintf(ubuf, "\\u%04x\\u%04x",
3893
- (0xd800 | (ch>>10)),
3894
- (0xdc00 | (ch & 0x3ff)));
3892
+ rc = snprintf(ubuf, (size_t)UBLen, "\\u%04x\\u%04x",
3893
+ (0xd800 | (ch>>10)),
3894
+ (0xdc00 | (ch & 0x3ff)));
38953895
if( rc != 12 )
38963896
{
3897
- rc = cson_rc.RangeError;
3897
+ rc = CSON_RC_RangeError;
38983898
break;
38993899
}
39003900
rc = f( state, ubuf, 12 );
39013901
}
39023902
continue;
@@ -3910,11 +3910,11 @@
39103910
}
39113911
}
39123912
39133913
int cson_object_iter_init( cson_object const * obj, cson_object_iterator * iter )
39143914
{
3915
- if( ! obj || !iter ) return cson_rc.ArgError;
3915
+ if( ! obj || !iter ) return CSON_RC_ArgError;
39163916
else
39173917
{
39183918
iter->obj = obj;
39193919
iter->pos = 0;
39203920
return 0;
@@ -3936,64 +3936,62 @@
39363936
}
39373937
}
39383938
39393939
static int cson_output_null( cson_data_dest_f f, void * state )
39403940
{
3941
- if( !f ) return cson_rc.ArgError;
3941
+ if( !f ) return CSON_RC_ArgError;
39423942
else
39433943
{
39443944
return f(state, "null", 4);
39453945
}
39463946
}
39473947
39483948
static int cson_output_bool( cson_value const * src, cson_data_dest_f f, void * state )
39493949
{
3950
- if( !f ) return cson_rc.ArgError;
3950
+ if( !f ) return CSON_RC_ArgError;
39513951
else
39523952
{
39533953
char const v = cson_value_get_bool(src);
39543954
return f(state, v ? "true" : "false", v ? 4 : 5);
39553955
}
39563956
}
39573957
39583958
static int cson_output_integer( cson_value const * src, cson_data_dest_f f, void * state )
39593959
{
3960
- if( !f ) return cson_rc.ArgError;
3961
- else if( !cson_value_is_integer(src) ) return cson_rc.TypeError;
3960
+ if( !f ) return CSON_RC_ArgError;
3961
+ else if( !cson_value_is_integer(src) ) return CSON_RC_TypeError;
39623962
else
39633963
{
39643964
enum { BufLen = 100 };
39653965
char b[BufLen];
39663966
int rc;
39673967
memset( b, 0, BufLen );
3968
- rc = sprintf( b, "%"CSON_INT_T_PFMT, cson_value_get_integer(src) )
3969
- /* Reminder: snprintf() is C99 */
3970
- ;
3968
+ rc = snprintf( b, (size_t)BufLen, "%"CSON_INT_T_PFMT,
3969
+ cson_value_get_integer(src) );
39713970
return ( rc<=0 )
3972
- ? cson_rc.RangeError
3971
+ ? CSON_RC_RangeError
39733972
: f( state, b, (unsigned int)rc )
39743973
;
39753974
}
39763975
}
39773976
39783977
static int cson_output_double( cson_value const * src, cson_data_dest_f f, void * state )
39793978
{
3980
- if( !f ) return cson_rc.ArgError;
3981
- else if( !cson_value_is_double(src) ) return cson_rc.TypeError;
3979
+ if( !f ) return CSON_RC_ArgError;
3980
+ else if( !cson_value_is_double(src) ) return CSON_RC_TypeError;
39823981
else
39833982
{
39843983
enum { BufLen = 128 /* this must be relatively large or huge
39853984
doubles can cause us to overrun here,
39863985
resulting in stack-smashing errors.
39873986
*/};
39883987
char b[BufLen];
39893988
int rc;
39903989
memset( b, 0, BufLen );
3991
- rc = sprintf( b, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(src) )
3992
- /* Reminder: snprintf() is C99 */
3993
- ;
3994
- if( rc<=0 ) return cson_rc.RangeError;
3990
+ rc = snprintf( b, (size_t)BufLen, "%"CSON_DOUBLE_T_PFMT,
3991
+ cson_value_get_double(src) );
3992
+ if( rc<=0 ) return CSON_RC_RangeError;
39953993
else if(1)
39963994
{ /* Strip trailing zeroes before passing it on... */
39973995
unsigned int urc = (unsigned int)rc;
39983996
char * pos = b + urc - 1;
39993997
for( ; ('0' == *pos) && urc && (*(pos-1) != '.'); --pos, --urc )
@@ -4012,12 +4010,12 @@
40124010
}
40134011
}
40144012
40154013
static int cson_output_string( cson_value const * src, char escapeFwdSlash, cson_data_dest_f f, void * state )
40164014
{
4017
- if( !f ) return cson_rc.ArgError;
4018
- else if( ! cson_value_is_string(src) ) return cson_rc.TypeError;
4015
+ if( !f ) return CSON_RC_ArgError;
4016
+ else if( ! cson_value_is_string(src) ) return CSON_RC_TypeError;
40194017
else
40204018
{
40214019
cson_string const * str = cson_value_get_string(src);
40224020
assert( NULL != str );
40234021
return cson_str_to_json(cson_string_cstr(str), str->length, escapeFwdSlash, f, state);
@@ -4075,11 +4073,11 @@
40754073
Returns 0 on success.
40764074
*/
40774075
static int cson_output_impl( cson_value const * src, cson_data_dest_f f, void * state,
40784076
cson_output_opt const * fmt, unsigned int level )
40794077
{
4080
- if( ! src || !f || !src->api ) return cson_rc.ArgError;
4078
+ if( ! src || !f || !src->api ) return CSON_RC_ArgError;
40814079
else
40824080
{
40834081
int rc = 0;
40844082
assert(fmt);
40854083
switch( src->api->typeID )
@@ -4105,11 +4103,11 @@
41054103
break;
41064104
case CSON_TYPE_OBJECT:
41074105
rc = cson_output_object( src, f, state, fmt, level );
41084106
break;
41094107
default:
4110
- rc = cson_rc.TypeError;
4108
+ rc = CSON_RC_TypeError;
41114109
break;
41124110
}
41134111
return rc;
41144112
}
41154113
}
@@ -4116,13 +4114,13 @@
41164114
41174115
41184116
static int cson_output_array( cson_value const * src, cson_data_dest_f f, void * state,
41194117
cson_output_opt const * fmt, unsigned int level )
41204118
{
4121
- if( !src || !f || !fmt ) return cson_rc.ArgError;
4122
- else if( ! cson_value_is_array(src) ) return cson_rc.TypeError;
4123
- else if( level > fmt->maxDepth ) return cson_rc.RangeError;
4119
+ if( !src || !f || !fmt ) return CSON_RC_ArgError;
4120
+ else if( ! cson_value_is_array(src) ) return CSON_RC_TypeError;
4121
+ else if( level > fmt->maxDepth ) return CSON_RC_RangeError;
41244122
else
41254123
{
41264124
int rc;
41274125
unsigned int i;
41284126
cson_value const * v;
@@ -4177,13 +4175,13 @@
41774175
}
41784176
41794177
static int cson_output_object( cson_value const * src, cson_data_dest_f f, void * state,
41804178
cson_output_opt const * fmt, unsigned int level )
41814179
{
4182
- if( !src || !f || !fmt ) return cson_rc.ArgError;
4183
- else if( ! cson_value_is_object(src) ) return cson_rc.TypeError;
4184
- else if( level > fmt->maxDepth ) return cson_rc.RangeError;
4180
+ if( !src || !f || !fmt ) return CSON_RC_ArgError;
4181
+ else if( ! cson_value_is_object(src) ) return CSON_RC_TypeError;
4182
+ else if( level > fmt->maxDepth ) return CSON_RC_RangeError;
41854183
else
41864184
{
41874185
int rc;
41884186
unsigned int i;
41894187
cson_kvp const * kvp;
@@ -4267,17 +4265,17 @@
42674265
return rc;
42684266
}
42694267
42704268
int cson_data_dest_FILE( void * state, void const * src, unsigned int n )
42714269
{
4272
- if( ! state ) return cson_rc.ArgError;
4270
+ if( ! state ) return CSON_RC_ArgError;
42734271
else if( !src || !n ) return 0;
42744272
else
42754273
{
42764274
return ( 1 == fwrite( src, n, 1, (FILE*) state ) )
42774275
? 0
4278
- : cson_rc.IOError;
4276
+ : CSON_RC_IOError;
42794277
}
42804278
}
42814279
42824280
int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * fmt )
42834281
{
@@ -4300,15 +4298,15 @@
43004298
return rc;
43014299
}
43024300
43034301
int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt )
43044302
{
4305
- if( !src || !dest ) return cson_rc.ArgError;
4303
+ if( !src || !dest ) return CSON_RC_ArgError;
43064304
else
43074305
{
43084306
FILE * f = fopen(dest,"wb");
4309
- if( !f ) return cson_rc.IOError;
4307
+ if( !f ) return CSON_RC_IOError;
43104308
else
43114309
{
43124310
int const rc = cson_output_FILE( src, f, fmt );
43134311
fclose(f);
43144312
return rc;
@@ -4317,15 +4315,15 @@
43174315
}
43184316
43194317
int cson_parse_filename( cson_value ** tgt, char const * src,
43204318
cson_parse_opt const * opt, cson_parse_info * err )
43214319
{
4322
- if( !src || !tgt ) return cson_rc.ArgError;
4320
+ if( !src || !tgt ) return CSON_RC_ArgError;
43234321
else
43244322
{
43254323
FILE * f = fopen(src, "r");
4326
- if( !f ) return cson_rc.IOError;
4324
+ if( !f ) return CSON_RC_IOError;
43274325
else
43284326
{
43294327
int const rc = cson_parse_FILE( tgt, f, opt, err );
43304328
fclose(f);
43314329
return rc;
@@ -4349,11 +4347,11 @@
43494347
A cson_data_source_f() implementation which requires the state argument
43504348
to be a properly populated (cson_data_source_StringSource_t*).
43514349
*/
43524350
static int cson_data_source_StringSource( void * state, void * dest, unsigned int * n )
43534351
{
4354
- if( !state || !n || !dest ) return cson_rc.ArgError;
4352
+ if( !state || !n || !dest ) return CSON_RC_ArgError;
43554353
else if( !*n ) return 0 /* ignore this */;
43564354
else
43574355
{
43584356
unsigned int i;
43594357
cson_data_source_StringSource_t * ss = (cson_data_source_StringSource_t*) state;
@@ -4368,12 +4366,12 @@
43684366
}
43694367
43704368
int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
43714369
cson_parse_opt const * opt, cson_parse_info * err )
43724370
{
4373
- if( ! tgt || !src ) return cson_rc.ArgError;
4374
- else if( !*src || (len<2/*2==len of {} and []*/) ) return cson_rc.RangeError;
4371
+ if( ! tgt || !src ) return CSON_RC_ArgError;
4372
+ else if( !*src || (len<2/*2==len of {} and []*/) ) return CSON_RC_RangeError;
43754373
else
43764374
{
43774375
cson_data_source_StringSource_t ss;
43784376
ss.str = ss.pos = src;
43794377
ss.end = src + len;
@@ -4386,18 +4384,18 @@
43864384
cson_buffer const * buf,
43874385
cson_parse_opt const * opt,
43884386
cson_parse_info * err )
43894387
{
43904388
return ( !tgt || !buf || !buf->mem || !buf->used )
4391
- ? cson_rc.ArgError
4389
+ ? CSON_RC_ArgError
43924390
: cson_parse_string( tgt, (char const *)buf->mem,
43934391
buf->used, opt, err );
43944392
}
43954393
43964394
int cson_buffer_reserve( cson_buffer * buf, cson_size_t n )
43974395
{
4398
- if( ! buf ) return cson_rc.ArgError;
4396
+ if( ! buf ) return CSON_RC_ArgError;
43994397
else if( 0 == n )
44004398
{
44014399
cson_free(buf->mem, "cson_buffer::mem");
44024400
*buf = cson_buffer_empty;
44034401
return 0;
@@ -4407,11 +4405,11 @@
44074405
return 0;
44084406
}
44094407
else
44104408
{
44114409
unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" );
4412
- if( ! x ) return cson_rc.AllocError;
4410
+ if( ! x ) return CSON_RC_AllocError;
44134411
memset( x + buf->used, 0, n - buf->used );
44144412
buf->mem = x;
44154413
buf->capacity = n;
44164414
++buf->timesExpanded;
44174415
return 0;
@@ -4434,11 +4432,11 @@
44344432
arg MUST be a (cson_buffer*). This function appends n bytes at
44354433
position arg->used, expanding the buffer as necessary.
44364434
*/
44374435
static int cson_data_dest_cson_buffer( void * arg, void const * data_, unsigned int n )
44384436
{
4439
- if( !arg ) return cson_rc.ArgError;
4437
+ if( !arg ) return CSON_RC_ArgError;
44404438
else if( ! n ) return 0;
44414439
else
44424440
{
44434441
cson_buffer * sb = (cson_buffer*)arg;
44444442
char const * data = (char const *)data_;
@@ -4446,12 +4444,12 @@
44464444
unsigned int i;
44474445
if( npos >= sb->capacity )
44484446
{
44494447
const cson_size_t oldCap = sb->capacity;
44504448
const cson_size_t asz = npos * 2;
4451
- if( asz < npos ) return cson_rc.ArgError; /* overflow */
4452
- else if( 0 != cson_buffer_reserve( sb, asz ) ) return cson_rc.AllocError;
4449
+ if( asz < npos ) return CSON_RC_ArgError; /* overflow */
4450
+ else if( 0 != cson_buffer_reserve( sb, asz ) ) return CSON_RC_AllocError;
44534451
assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
44544452
/* make sure it gets NUL terminated. */
44554453
memset( sb->mem + oldCap, 0, (sb->capacity - oldCap) );
44564454
}
44574455
for( i = 0; i < n; ++i, ++sb->used )
@@ -4533,19 +4531,19 @@
45334531
return (pos > *inp) ? 1 : 0;
45344532
}
45354533
45364534
int cson_object_fetch_sub2( cson_object const * obj, cson_value ** tgt, char const * path )
45374535
{
4538
- if( ! obj || !path ) return cson_rc.ArgError;
4539
- else if( !*path || !*(1+path) ) return cson_rc.RangeError;
4536
+ if( ! obj || !path ) return CSON_RC_ArgError;
4537
+ else if( !*path || !*(1+path) ) return CSON_RC_RangeError;
45404538
else return cson_object_fetch_sub(obj, tgt, path+1, *path);
45414539
}
45424540
45434541
int cson_object_fetch_sub( cson_object const * obj, cson_value ** tgt, char const * path, char sep )
45444542
{
4545
- if( ! obj || !path ) return cson_rc.ArgError;
4546
- else if( !*path || !sep ) return cson_rc.RangeError;
4543
+ if( ! obj || !path ) return CSON_RC_ArgError;
4544
+ else if( !*path || !sep ) return CSON_RC_RangeError;
45474545
else
45484546
{
45494547
char const * beg = path;
45504548
char const * end = NULL;
45514549
int rc;
@@ -4565,26 +4563,26 @@
45654563
++tokenCount;
45664564
beg = end;
45674565
end = NULL;
45684566
}
45694567
}
4570
- if( 0 == tokenCount ) return cson_rc.RangeError;
4568
+ if( 0 == tokenCount ) return CSON_RC_RangeError;
45714569
beg = path;
45724570
end = NULL;
45734571
for( i = 0; i < tokenCount; ++i, beg=end, end=NULL )
45744572
{
45754573
rc = cson_next_token( &beg, sep, &end );
45764574
assert( 1 == rc );
45774575
assert( beg != end );
45784576
assert( end > beg );
45794577
len = end - beg;
4580
- if( len > (BufSize-1) ) return cson_rc.RangeError;
4578
+ if( len > (BufSize-1) ) return CSON_RC_RangeError;
45814579
memset( buf, 0, len + 1 );
45824580
memcpy( buf, beg, len );
45834581
buf[len] = 0;
45844582
cv = cson_object_get( curObj, buf );
4585
- if( NULL == cv ) return cson_rc.NotFoundError;
4583
+ if( NULL == cv ) return CSON_RC_NotFoundError;
45864584
else if( i == (tokenCount-1) )
45874585
{
45884586
if(tgt) *tgt = cv;
45894587
return 0;
45904588
}
@@ -4594,15 +4592,15 @@
45944592
assert((NULL != curObj) && "Detected mis-management of internal memory!");
45954593
}
45964594
/* TODO: arrays. Requires numeric parsing for the index. */
45974595
else
45984596
{
4599
- return cson_rc.NotFoundError;
4597
+ return CSON_RC_NotFoundError;
46004598
}
46014599
}
46024600
assert( i == tokenCount );
4603
- return cson_rc.NotFoundError;
4601
+ return CSON_RC_NotFoundError;
46044602
}
46054603
}
46064604
46074605
cson_value * cson_object_get_sub( cson_object const * obj, char const * path, char sep )
46084606
{
@@ -4838,24 +4836,26 @@
48384836
}
48394837
case CSON_TYPE_STRING: {
48404838
cson_string const * jstr = cson_value_get_string(orig);
48414839
unsigned const int slen = cson_string_length_bytes( jstr );
48424840
assert( NULL != jstr );
4843
- v = cson_strdup( cson_string_cstr( jstr ), slen );
4841
+ v = cson_strdup( cson_string_cstr( jstr ), slen );
48444842
break;
48454843
}
48464844
case CSON_TYPE_INTEGER: {
48474845
char buf[BufSize] = {0};
4848
- if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) )
4846
+ if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_INT_T_PFMT,
4847
+ cson_value_get_integer(orig)) )
48494848
{
48504849
v = cson_strdup( buf, strlen(buf) );
48514850
}
48524851
break;
48534852
}
48544853
case CSON_TYPE_DOUBLE: {
48554854
char buf[BufSize] = {0};
4856
- if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) )
4855
+ if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_DOUBLE_T_PFMT,
4856
+ cson_value_get_double(orig)) )
48574857
{
48584858
v = cson_strdup( buf, strlen(buf) );
48594859
}
48604860
break;
48614861
}
@@ -4891,24 +4891,26 @@
48914891
}
48924892
case CSON_TYPE_STRING: {
48934893
cson_string const * jstr = cson_value_get_string(orig);
48944894
unsigned const int slen = cson_string_length_bytes( jstr );
48954895
assert( NULL != jstr );
4896
- v = cson_strdup( cson_string_cstr( jstr ), slen );
4896
+ v = cson_strdup( cson_string_cstr( jstr ), slen );
48974897
break;
48984898
}
48994899
case CSON_TYPE_INTEGER: {
49004900
char buf[BufSize] = {0};
4901
- if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) )
4901
+ if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_INT_T_PFMT,
4902
+ cson_value_get_integer(orig)) )
49024903
{
49034904
v = cson_strdup( buf, strlen(buf) );
49044905
}
49054906
break;
49064907
}
49074908
case CSON_TYPE_DOUBLE: {
49084909
char buf[BufSize] = {0};
4909
- if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) )
4910
+ if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_DOUBLE_T_PFMT,
4911
+ cson_value_get_double(orig)) )
49104912
{
49114913
v = cson_strdup( buf, strlen(buf) );
49124914
}
49134915
break;
49144916
}
@@ -4988,11 +4990,11 @@
49884990
cson_object_iterator iter = cson_object_iterator_empty;
49894991
int rc;
49904992
char const replace = (flags & CSON_MERGE_REPLACE);
49914993
char const recurse = !(flags & CSON_MERGE_NO_RECURSE);
49924994
cson_kvp const * kvp;
4993
- if((!dest || !src) || (dest==src)) return cson_rc.ArgError;
4995
+ if((!dest || !src) || (dest==src)) return CSON_RC_ArgError;
49944996
rc = cson_object_iter_init( src, &iter );
49954997
if(rc) return rc;
49964998
while( (kvp = cson_object_iter_next(&iter) ) )
49974999
{
49985000
cson_string * key = cson_kvp_key(kvp);
@@ -5052,11 +5054,11 @@
50525054
int cson_parse_argv_flags( int argc, char const * const * argv,
50535055
cson_object ** tgt, unsigned int * count ){
50545056
cson_object * o = NULL;
50555057
int rc = 0;
50565058
int i = 0;
5057
- if(argc<1 || !argc || !tgt) return cson_rc.ArgError;
5059
+ if(argc<1 || !argc || !tgt) return CSON_RC_ArgError;
50585060
o = *tgt ? *tgt : cson_new_object();
50595061
if(count) *count = 0;
50605062
for( i = 0; i < argc; ++i ){
50615063
char const * arg = argv[i];
50625064
char const * key = arg;
@@ -5068,11 +5070,11 @@
50685070
if(!*key) continue;
50695071
pos = key;
50705072
while( *pos && ('=' != *pos)) ++pos;
50715073
k = cson_new_string(key, pos-key);
50725074
if(!k){
5073
- rc = cson_rc.AllocError;
5075
+ rc = CSON_RC_AllocError;
50745076
break;
50755077
}
50765078
if(!*pos){ /** --key */
50775079
v = cson_value_true();
50785080
}else{ /** --key=...*/
@@ -5389,11 +5391,11 @@
53895391
cson_string * colName = NULL;
53905392
int i = 0;
53915393
int rc = 0;
53925394
cson_value * currentValue = NULL;
53935395
int const colCount = sqlite3_column_count(st);
5394
- if( !colCount || (colCount>(int)cson_array_length_get(colNames)) ) {
5396
+ if( !colCount || (colCount>cson_array_length_get(colNames)) ) {
53955397
return NULL;
53965398
}
53975399
rootV = cson_value_new_object();
53985400
if(!rootV) return NULL;
53995401
root = cson_value_get_object(rootV);
54005402
--- extsrc/cson_amalgamation.c
+++ extsrc/cson_amalgamation.c
@@ -1435,11 +1435,10 @@
1435 #if defined(__cplusplus)
1436 extern "C" {
1437 #endif
1438
1439
1440
1441 /**
1442 This type holds the "vtbl" for type-specific operations when
1443 working with cson_value objects.
1444
1445 All cson_values of a given logical type share a pointer to a single
@@ -1686,12 +1685,12 @@
1686 : 0;
1687 }
1688
1689 char const * cson_rc_string(int rc)
1690 {
1691 if(0 == rc) return "OK";
1692 #define CHECK(N) else if(cson_rc.N == rc ) return #N
1693 CHECK(OK);
1694 CHECK(ArgError);
1695 CHECK(RangeError);
1696 CHECK(TypeError);
1697 CHECK(IOError);
@@ -1708,11 +1707,12 @@
1708 CHECK(Parse_INVALID_NUMBER);
1709 CHECK(Parse_NESTING_DEPTH_REACHED);
1710 CHECK(Parse_UNBALANCED_COLLECTION);
1711 CHECK(Parse_EXPECTED_KEY);
1712 CHECK(Parse_EXPECTED_COLON);
1713 else return "UnknownError";
 
1714 #undef CHECK
1715 }
1716
1717 /**
1718 If CSON_LOG_ALLOC is true then the cson_malloc/realloc/free() routines
@@ -1854,11 +1854,11 @@
1854 }
1855
1856 #if 0
1857 int cson_value_refcount_set( cson_value * cv, unsigned short rc )
1858 {
1859 if( NULL == cv ) return cson_rc.ArgError;
1860 else
1861 {
1862 cv->refcount = rc;
1863 return 0;
1864 }
@@ -1865,14 +1865,14 @@
1865 }
1866 #endif
1867
1868 int cson_value_add_reference( cson_value * cv )
1869 {
1870 if( NULL == cv ) return cson_rc.ArgError;
1871 else if( (cv->refcount+1) < cv->refcount )
1872 {
1873 return cson_rc.RangeError;
1874 }
1875 else
1876 {
1877 cson_refcount_incr( cv );
1878 return 0;
@@ -2335,11 +2335,11 @@
2335 val->refcount = rc;
2336 }
2337 }
2338 }
2339
2340 static cson_value * cson_value_array_alloc()
2341 {
2342 cson_value * v = cson_value_new(CSON_TYPE_ARRAY,0);
2343 if( NULL != v )
2344 {
2345 cson_array * ar = CSON_ARRAY(v);
@@ -2347,11 +2347,11 @@
2347 *ar = cson_array_empty;
2348 }
2349 return v;
2350 }
2351
2352 static cson_value * cson_value_object_alloc()
2353 {
2354 cson_value * v = cson_value_new(CSON_TYPE_OBJECT,0);
2355 if( NULL != v )
2356 {
2357 cson_object * obj = CSON_OBJ(v);
@@ -2359,28 +2359,28 @@
2359 *obj = cson_object_empty;
2360 }
2361 return v;
2362 }
2363
2364 cson_value * cson_value_new_object()
2365 {
2366 return cson_value_object_alloc();
2367 }
2368
2369 cson_object * cson_new_object()
2370 {
2371
2372 return cson_value_get_object( cson_value_new_object() );
2373 }
2374
2375 cson_value * cson_value_new_array()
2376 {
2377 return cson_value_array_alloc();
2378 }
2379
2380
2381 cson_array * cson_new_array()
2382 {
2383 return cson_value_get_array( cson_value_new_array() );
2384 }
2385
2386 /**
@@ -2502,11 +2502,11 @@
2502 int rc;
2503 enum { BufSize = 1024 * 4 };
2504 char rbuf[BufSize];
2505 size_t total = 0;
2506 unsigned int rlen = 0;
2507 if( ! dest || ! src ) return cson_rc.ArgError;
2508 dest->used = 0;
2509 while(1)
2510 {
2511 rlen = BufSize;
2512 rc = src( state, rbuf, &rlen );
@@ -2530,16 +2530,16 @@
2530 }
2531
2532 int cson_data_source_FILE( void * state, void * dest, unsigned int * n )
2533 {
2534 FILE * f = (FILE*) state;
2535 if( ! state || ! n || !dest ) return cson_rc.ArgError;
2536 else if( !*n ) return cson_rc.RangeError;
2537 *n = (unsigned int)fread( dest, 1, *n, f );
2538 if( !*n )
2539 {
2540 return feof(f) ? 0 : cson_rc.IOError;
2541 }
2542 return 0;
2543 }
2544
2545 int cson_parse_FILE( cson_value ** tgt, FILE * src,
@@ -2553,11 +2553,11 @@
2553 {
2554 /**
2555 FIXME: move the to-bool operation into cson_value_api, like we
2556 do in the C++ API.
2557 */
2558 if( ! val || !val->api ) return cson_rc.ArgError;
2559 else
2560 {
2561 int rc = 0;
2562 char b = 0;
2563 switch( val->api->typeID )
@@ -2588,11 +2588,11 @@
2588 cson_value_fetch_double( val, &d );
2589 b = (0.0==d) ? 0 : 1;
2590 break;
2591 }
2592 default:
2593 rc = cson_rc.TypeError;
2594 break;
2595 }
2596 if( v ) *v = b;
2597 return rc;
2598 }
@@ -2605,11 +2605,11 @@
2605 return i;
2606 }
2607
2608 int cson_value_fetch_integer( cson_value const * val, cson_int_t * v )
2609 {
2610 if( ! val || !val->api ) return cson_rc.ArgError;
2611 else
2612 {
2613 cson_int_t i = 0;
2614 int rc = 0;
2615 switch(val->api->typeID)
@@ -2641,11 +2641,11 @@
2641 }
2642 case CSON_TYPE_STRING:
2643 case CSON_TYPE_ARRAY:
2644 case CSON_TYPE_OBJECT:
2645 default:
2646 rc = cson_rc.TypeError;
2647 break;
2648 }
2649 if(!rc && v) *v = i;
2650 return rc;
2651 }
@@ -2658,11 +2658,11 @@
2658 return i;
2659 }
2660
2661 int cson_value_fetch_double( cson_value const * val, cson_double_t * v )
2662 {
2663 if( ! val || !val->api ) return cson_rc.ArgError;
2664 else
2665 {
2666 cson_double_t d = 0.0;
2667 int rc = 0;
2668 switch(val->api->typeID)
@@ -2687,11 +2687,11 @@
2687 cson_double_t const* dv = CSON_DBL(val);
2688 d = dv ? *dv : 0.0;
2689 break;
2690 }
2691 default:
2692 rc = cson_rc.TypeError;
2693 break;
2694 }
2695 if(v) *v = d;
2696 return rc;
2697 }
@@ -2704,12 +2704,12 @@
2704 return i;
2705 }
2706
2707 int cson_value_fetch_string( cson_value const * val, cson_string ** dest )
2708 {
2709 if( ! val || ! dest ) return cson_rc.ArgError;
2710 else if( ! cson_value_is_string(val) ) return cson_rc.TypeError;
2711 else
2712 {
2713 if( dest ) *dest = CSON_STR(val);
2714 return 0;
2715 }
@@ -2727,12 +2727,12 @@
2727 return cson_string_cstr( cson_value_get_string(val) );
2728 }
2729
2730 int cson_value_fetch_object( cson_value const * val, cson_object ** obj )
2731 {
2732 if( ! val ) return cson_rc.ArgError;
2733 else if( ! cson_value_is_object(val) ) return cson_rc.TypeError;
2734 else
2735 {
2736 if(obj) *obj = CSON_OBJ(val);
2737 return 0;
2738 }
@@ -2744,12 +2744,12 @@
2744 return obj;
2745 }
2746
2747 int cson_value_fetch_array( cson_value const * val, cson_array ** ar)
2748 {
2749 if( ! val ) return cson_rc.ArgError;
2750 else if( !cson_value_is_array(val) ) return cson_rc.TypeError;
2751 else
2752 {
2753 if(ar) *ar = CSON_ARRAY(val);
2754 return 0;
2755 }
@@ -2760,11 +2760,11 @@
2760 cson_array * ar = NULL;
2761 cson_value_fetch_array( v, &ar );
2762 return ar;
2763 }
2764
2765 cson_kvp * cson_kvp_alloc()
2766 {
2767 cson_kvp * kvp = (cson_kvp*)cson_malloc(sizeof(cson_kvp),"cson_kvp");
2768 if( kvp )
2769 {
2770 *kvp = cson_kvp_empty;
@@ -2774,20 +2774,20 @@
2774
2775
2776
2777 int cson_array_append( cson_array * ar, cson_value * v )
2778 {
2779 if( !ar || !v ) return cson_rc.ArgError;
2780 else if( (ar->list.count+1) < ar->list.count ) return cson_rc.RangeError;
2781 else
2782 {
2783 if( !ar->list.alloced || (ar->list.count == ar->list.alloced-1))
2784 {
2785 unsigned int const n = ar->list.count ? (ar->list.count*2) : 7;
2786 if( n > cson_value_list_reserve( &ar->list, n ) )
2787 {
2788 return cson_rc.AllocError;
2789 }
2790 }
2791 return cson_array_set( ar, ar->list.count, v );
2792 }
2793 }
@@ -2832,20 +2832,20 @@
2832 cson_value * cson_value_new_bool( char v )
2833 {
2834 return v ? &CSON_SPECIAL_VALUES[CSON_VAL_TRUE] : &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
2835 }
2836
2837 cson_value * cson_value_true()
2838 {
2839 return &CSON_SPECIAL_VALUES[CSON_VAL_TRUE];
2840 }
2841 cson_value * cson_value_false()
2842 {
2843 return &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
2844 }
2845
2846 cson_value * cson_value_null()
2847 {
2848 return &CSON_SPECIAL_VALUES[CSON_VAL_NULL];
2849 }
2850
2851 cson_value * cson_new_int( cson_int_t v )
@@ -2917,12 +2917,12 @@
2917 return cson_string_value( cson_new_string(str, len) );
2918 }
2919
2920 int cson_array_value_fetch( cson_array const * ar, unsigned int pos, cson_value ** v )
2921 {
2922 if( !ar) return cson_rc.ArgError;
2923 if( pos >= ar->list.count ) return cson_rc.RangeError;
2924 else
2925 {
2926 if(v) *v = ar->list.list[pos];
2927 return 0;
2928 }
@@ -2935,11 +2935,11 @@
2935 return v;
2936 }
2937
2938 int cson_array_length_fetch( cson_array const * ar, unsigned int * v )
2939 {
2940 if( ! ar || !v ) return cson_rc.ArgError;
2941 else
2942 {
2943 if(v) *v = ar->list.count;
2944 return 0;
2945 }
@@ -2952,11 +2952,11 @@
2952 return i;
2953 }
2954
2955 int cson_array_reserve( cson_array * ar, unsigned int size )
2956 {
2957 if( ! ar ) return cson_rc.ArgError;
2958 else if( size <= ar->list.alloced )
2959 {
2960 /* We don't want to introduce a can of worms by trying to
2961 handle the cleanup from here.
2962 */
@@ -2963,24 +2963,24 @@
2963 return 0;
2964 }
2965 else
2966 {
2967 return (ar->list.alloced > cson_value_list_reserve( &ar->list, size ))
2968 ? cson_rc.AllocError
2969 : 0
2970 ;
2971 }
2972 }
2973
2974 int cson_array_set( cson_array * ar, unsigned int ndx, cson_value * v )
2975 {
2976 if( !ar || !v ) return cson_rc.ArgError;
2977 else if( (ndx+1) < ndx) /* overflow */return cson_rc.RangeError;
2978 else
2979 {
2980 unsigned const int len = cson_value_list_reserve( &ar->list, ndx+1 );
2981 if( len <= ndx ) return cson_rc.AllocError;
2982 else
2983 {
2984 cson_value * old = ar->list.list[ndx];
2985 if( old )
2986 {
@@ -3076,18 +3076,18 @@
3076 }
3077 #endif
3078
3079 int cson_object_unset( cson_object * obj, char const * key )
3080 {
3081 if( ! obj || !key || !*key ) return cson_rc.ArgError;
3082 else
3083 {
3084 unsigned int ndx = 0;
3085 cson_kvp * kvp = cson_object_search_impl( obj, key, &ndx );
3086 if( ! kvp )
3087 {
3088 return cson_rc.NotFoundError;
3089 }
3090 assert( obj->kvp.count > 0 );
3091 assert( obj->kvp.list[ndx] == kvp );
3092 cson_kvp_free( kvp );
3093 obj->kvp.list[ndx] = NULL;
@@ -3109,21 +3109,21 @@
3109 }
3110 }
3111
3112 int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v )
3113 {
3114 if( !obj || !key ) return cson_rc.ArgError;
3115 else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) );
3116 else
3117 {
3118 char const * cKey;
3119 cson_value * vKey;
3120 cson_kvp * kvp;
3121 vKey = cson_string_value(key);
3122 assert(vKey && (key==CSON_STR(vKey)));
3123 if( vKey == CSON_VCAST(obj) ){
3124 return cson_rc.ArgError;
3125 }
3126 cKey = cson_string_cstr(key);
3127 kvp = cson_object_search_impl( obj, cKey, NULL );
3128 if( kvp )
3129 { /* "I told 'em we've already got one!" */
@@ -3142,19 +3142,19 @@
3142 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3143 { /* reserve space */
3144 unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
3145 if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
3146 {
3147 return cson_rc.AllocError;
3148 }
3149 }
3150 { /* insert new item... */
3151 int rc = 0;
3152 kvp = cson_kvp_alloc();
3153 if( ! kvp )
3154 {
3155 return cson_rc.AllocError;
3156 }
3157 rc = cson_kvp_list_append( &obj->kvp, kvp );
3158 if( 0 != rc )
3159 {
3160 cson_kvp_free(kvp);
@@ -3174,19 +3174,19 @@
3174 }
3175
3176 }
3177 int cson_object_set( cson_object * obj, char const * key, cson_value * v )
3178 {
3179 if( ! obj || !key || !*key ) return cson_rc.ArgError;
3180 else if( NULL == v )
3181 {
3182 return cson_object_unset( obj, key );
3183 }
3184 else
3185 {
3186 cson_string * cs = cson_new_string(key,strlen(key));
3187 if(!cs) return cson_rc.AllocError;
3188 else
3189 {
3190 int const rc = cson_object_set_s(obj, cs, v);
3191 if(rc) cson_value_free(cson_string_value(cs));
3192 return rc;
@@ -3237,13 +3237,13 @@
3237 }
3238 }
3239 /** @internal
3240
3241 If p->node is-a Object then value is inserted into the object
3242 using p->key. In any other case cson_rc.InternalError is returned.
3243
3244 Returns cson_rc.AllocError if an allocation fails.
3245
3246 Returns 0 on success. On error, parsing must be ceased immediately.
3247
3248 Ownership of val is ALWAYS TRANSFERED to this function. If this
3249 function fails, val will be cleaned up and destroyed. (This
@@ -3267,18 +3267,18 @@
3267 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3268 {
3269 if( obj->kvp.alloced > cson_kvp_list_reserve( &obj->kvp, obj->kvp.count ? (obj->kvp.count*2) : 5 ) )
3270 {
3271 cson_value_free(val);
3272 return cson_rc.AllocError;
3273 }
3274 }
3275 kvp = cson_kvp_alloc();
3276 if( ! kvp )
3277 {
3278 cson_value_free(val);
3279 return cson_rc.AllocError;
3280 }
3281 kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
3282 assert(0 == kvp->key->refcount);
3283 cson_refcount_incr(kvp->key);
3284 p->ckey = NULL;
@@ -3296,11 +3296,11 @@
3296 return rc;
3297 }
3298 else
3299 {
3300 if(val) cson_value_free(val);
3301 return p->errNo = cson_rc.InternalError;
3302 }
3303
3304 }
3305
3306 /** @internal
@@ -3337,11 +3337,11 @@
3337 return rc;
3338 }
3339 else
3340 { /* WTF? */
3341 assert( 0 && "Internal error in cson_parser code" );
3342 return p->errNo = cson_rc.InternalError;
3343 }
3344 }
3345
3346 /**
3347 Callback for JSON_parser API. Reminder: it returns 0 (meaning false)
@@ -3349,20 +3349,20 @@
3349 */
3350 static int cson_parse_callback( void * cx, int type, JSON_value const * value )
3351 {
3352 cson_parser * p = (cson_parser *)cx;
3353 int rc = 0;
3354 #define ALLOC_V(T,V) cson_value * v = cson_value_new_##T(V); if( ! v ) { rc = cson_rc.AllocError; break; }
3355 switch(type) {
3356 case JSON_T_ARRAY_BEGIN:
3357 case JSON_T_OBJECT_BEGIN: {
3358 cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
3359 ? cson_value_new_array()
3360 : cson_value_new_object();
3361 if( ! obja )
3362 {
3363 p->errNo = cson_rc.AllocError;
3364 break;
3365 }
3366 if( 0 != rc ) break;
3367 if( ! p->root )
3368 {
@@ -3395,11 +3395,11 @@
3395 }
3396 case JSON_T_ARRAY_END:
3397 case JSON_T_OBJECT_END: {
3398 if( 0 == p->stack.list.count )
3399 {
3400 rc = cson_rc.RangeError;
3401 break;
3402 }
3403 #if CSON_OBJECT_PROPS_SORT
3404 if( cson_value_is_object(p->node) )
3405 {/* kludge: the parser uses custom cson_object property
@@ -3481,26 +3481,26 @@
3481 case JSON_T_KEY: {
3482 assert(!p->ckey);
3483 p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length );
3484 if( ! p->ckey )
3485 {
3486 rc = cson_rc.AllocError;
3487 break;
3488 }
3489 ++p->totalKeyCount;
3490 break;
3491 }
3492 case JSON_T_STRING: {
3493 cson_value * v = cson_value_new_string( value->vu.str.value, value->vu.str.length );
3494 rc = ( NULL == v )
3495 ? cson_rc.AllocError
3496 : cson_parser_push_value( p, v );
3497 break;
3498 }
3499 default:
3500 assert(0);
3501 rc = cson_rc.InternalError;
3502 break;
3503 }
3504 #undef ALLOC_V
3505 return ((p->errNo = rc)) ? 0 : 1;
3506 }
@@ -3512,22 +3512,22 @@
3512 static int cson_json_err_to_rc( JSON_error jrc )
3513 {
3514 switch(jrc)
3515 {
3516 case JSON_E_NONE: return 0;
3517 case JSON_E_INVALID_CHAR: return cson_rc.Parse_INVALID_CHAR;
3518 case JSON_E_INVALID_KEYWORD: return cson_rc.Parse_INVALID_KEYWORD;
3519 case JSON_E_INVALID_ESCAPE_SEQUENCE: return cson_rc.Parse_INVALID_ESCAPE_SEQUENCE;
3520 case JSON_E_INVALID_UNICODE_SEQUENCE: return cson_rc.Parse_INVALID_UNICODE_SEQUENCE;
3521 case JSON_E_INVALID_NUMBER: return cson_rc.Parse_INVALID_NUMBER;
3522 case JSON_E_NESTING_DEPTH_REACHED: return cson_rc.Parse_NESTING_DEPTH_REACHED;
3523 case JSON_E_UNBALANCED_COLLECTION: return cson_rc.Parse_UNBALANCED_COLLECTION;
3524 case JSON_E_EXPECTED_KEY: return cson_rc.Parse_EXPECTED_KEY;
3525 case JSON_E_EXPECTED_COLON: return cson_rc.Parse_EXPECTED_COLON;
3526 case JSON_E_OUT_OF_MEMORY: return cson_rc.AllocError;
3527 default:
3528 return cson_rc.InternalError;
3529 }
3530 }
3531
3532 /** @internal
3533
@@ -3543,11 +3543,11 @@
3543 any other items inserted into it (or under it) during the parsing
3544 process.
3545 */
3546 static int cson_parser_clean( cson_parser * p )
3547 {
3548 if( ! p ) return cson_rc.ArgError;
3549 else
3550 {
3551 if( p->p )
3552 {
3553 delete_JSON_parser(p->p);
@@ -3574,11 +3574,11 @@
3574 cson_parse_opt const opt = opt_ ? *opt_ : cson_parse_opt_empty;
3575 int rc = 0;
3576 unsigned int len = 1;
3577 cson_parse_info info = info_ ? *info_ : cson_parse_info_empty;
3578 cson_parser p = cson_parser_empty;
3579 if( ! tgt || ! src ) return cson_rc.ArgError;
3580
3581 {
3582 JSON_config jopt = {0};
3583 init_JSON_config( &jopt );
3584 jopt.allow_comments = opt.allowComments;
@@ -3587,11 +3587,11 @@
3587 jopt.handle_floats_manually = 0;
3588 jopt.callback = cson_parse_callback;
3589 p.p = new_JSON_parser(&jopt);
3590 if( ! p.p )
3591 {
3592 return cson_rc.AllocError;
3593 }
3594 }
3595
3596 do
3597 { /* FIXME: buffer the input in multi-kb chunks. */
@@ -3608,11 +3608,11 @@
3608 }
3609 if( ! JSON_parser_char(p.p, ch[0]) )
3610 {
3611 rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
3612 if(0==rc) rc = p.errNo;
3613 if(0==rc) rc = cson_rc.InternalError;
3614 info.errorCode = rc;
3615 break;
3616 }
3617 if( '\n' != ch[0]) ++info.col;
3618 } while(1);
@@ -3630,11 +3630,11 @@
3630 if( ! JSON_parser_done(p.p) )
3631 {
3632 rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
3633 cson_parser_clean(&p);
3634 if(0==rc) rc = p.errNo;
3635 if(0==rc) rc = cson_rc.InternalError;
3636 }
3637 else
3638 {
3639 cson_value * root = p.root;
3640 p.root = NULL;
@@ -3652,11 +3652,11 @@
3652 */;
3653 *tgt = root;
3654 }
3655 else
3656 { /* then can happen on empty input. */
3657 rc = cson_rc.UnknownError;
3658 }
3659 }
3660 return rc;
3661 }
3662
@@ -3771,11 +3771,11 @@
3771 */
3772 static int cson_str_to_json( char const * str, unsigned int len,
3773 char escapeFwdSlash,
3774 cson_data_dest_f f, void * state )
3775 {
3776 if( NULL == f ) return cson_rc.ArgError;
3777 else if( !str || !*str || (0 == len) )
3778 { /* special case for 0-length strings. */
3779 return f( state, "\"\"", 2 );
3780 }
3781 else
@@ -3877,26 +3877,26 @@
3877 #if defined(CSON_FOSSIL_MODE)
3878 assume_latin1:
3879 #endif
3880 memset(ubuf,0,UBLen);
3881 if(ch <= 0xFFFF){
3882 rc = sprintf(ubuf, "\\u%04x",ch);
3883 if( rc != 6 )
3884 {
3885 rc = cson_rc.RangeError;
3886 break;
3887 }
3888 rc = f( state, ubuf, 6 );
3889 }else{ /* encode as a UTF16 surrogate pair */
3890 /* http://unicodebook.readthedocs.org/en/latest/unicode_encodings.html#surrogates */
3891 ch -= 0x10000;
3892 rc = sprintf(ubuf, "\\u%04x\\u%04x",
3893 (0xd800 | (ch>>10)),
3894 (0xdc00 | (ch & 0x3ff)));
3895 if( rc != 12 )
3896 {
3897 rc = cson_rc.RangeError;
3898 break;
3899 }
3900 rc = f( state, ubuf, 12 );
3901 }
3902 continue;
@@ -3910,11 +3910,11 @@
3910 }
3911 }
3912
3913 int cson_object_iter_init( cson_object const * obj, cson_object_iterator * iter )
3914 {
3915 if( ! obj || !iter ) return cson_rc.ArgError;
3916 else
3917 {
3918 iter->obj = obj;
3919 iter->pos = 0;
3920 return 0;
@@ -3936,64 +3936,62 @@
3936 }
3937 }
3938
3939 static int cson_output_null( cson_data_dest_f f, void * state )
3940 {
3941 if( !f ) return cson_rc.ArgError;
3942 else
3943 {
3944 return f(state, "null", 4);
3945 }
3946 }
3947
3948 static int cson_output_bool( cson_value const * src, cson_data_dest_f f, void * state )
3949 {
3950 if( !f ) return cson_rc.ArgError;
3951 else
3952 {
3953 char const v = cson_value_get_bool(src);
3954 return f(state, v ? "true" : "false", v ? 4 : 5);
3955 }
3956 }
3957
3958 static int cson_output_integer( cson_value const * src, cson_data_dest_f f, void * state )
3959 {
3960 if( !f ) return cson_rc.ArgError;
3961 else if( !cson_value_is_integer(src) ) return cson_rc.TypeError;
3962 else
3963 {
3964 enum { BufLen = 100 };
3965 char b[BufLen];
3966 int rc;
3967 memset( b, 0, BufLen );
3968 rc = sprintf( b, "%"CSON_INT_T_PFMT, cson_value_get_integer(src) )
3969 /* Reminder: snprintf() is C99 */
3970 ;
3971 return ( rc<=0 )
3972 ? cson_rc.RangeError
3973 : f( state, b, (unsigned int)rc )
3974 ;
3975 }
3976 }
3977
3978 static int cson_output_double( cson_value const * src, cson_data_dest_f f, void * state )
3979 {
3980 if( !f ) return cson_rc.ArgError;
3981 else if( !cson_value_is_double(src) ) return cson_rc.TypeError;
3982 else
3983 {
3984 enum { BufLen = 128 /* this must be relatively large or huge
3985 doubles can cause us to overrun here,
3986 resulting in stack-smashing errors.
3987 */};
3988 char b[BufLen];
3989 int rc;
3990 memset( b, 0, BufLen );
3991 rc = sprintf( b, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(src) )
3992 /* Reminder: snprintf() is C99 */
3993 ;
3994 if( rc<=0 ) return cson_rc.RangeError;
3995 else if(1)
3996 { /* Strip trailing zeroes before passing it on... */
3997 unsigned int urc = (unsigned int)rc;
3998 char * pos = b + urc - 1;
3999 for( ; ('0' == *pos) && urc && (*(pos-1) != '.'); --pos, --urc )
@@ -4012,12 +4010,12 @@
4012 }
4013 }
4014
4015 static int cson_output_string( cson_value const * src, char escapeFwdSlash, cson_data_dest_f f, void * state )
4016 {
4017 if( !f ) return cson_rc.ArgError;
4018 else if( ! cson_value_is_string(src) ) return cson_rc.TypeError;
4019 else
4020 {
4021 cson_string const * str = cson_value_get_string(src);
4022 assert( NULL != str );
4023 return cson_str_to_json(cson_string_cstr(str), str->length, escapeFwdSlash, f, state);
@@ -4075,11 +4073,11 @@
4075 Returns 0 on success.
4076 */
4077 static int cson_output_impl( cson_value const * src, cson_data_dest_f f, void * state,
4078 cson_output_opt const * fmt, unsigned int level )
4079 {
4080 if( ! src || !f || !src->api ) return cson_rc.ArgError;
4081 else
4082 {
4083 int rc = 0;
4084 assert(fmt);
4085 switch( src->api->typeID )
@@ -4105,11 +4103,11 @@
4105 break;
4106 case CSON_TYPE_OBJECT:
4107 rc = cson_output_object( src, f, state, fmt, level );
4108 break;
4109 default:
4110 rc = cson_rc.TypeError;
4111 break;
4112 }
4113 return rc;
4114 }
4115 }
@@ -4116,13 +4114,13 @@
4116
4117
4118 static int cson_output_array( cson_value const * src, cson_data_dest_f f, void * state,
4119 cson_output_opt const * fmt, unsigned int level )
4120 {
4121 if( !src || !f || !fmt ) return cson_rc.ArgError;
4122 else if( ! cson_value_is_array(src) ) return cson_rc.TypeError;
4123 else if( level > fmt->maxDepth ) return cson_rc.RangeError;
4124 else
4125 {
4126 int rc;
4127 unsigned int i;
4128 cson_value const * v;
@@ -4177,13 +4175,13 @@
4177 }
4178
4179 static int cson_output_object( cson_value const * src, cson_data_dest_f f, void * state,
4180 cson_output_opt const * fmt, unsigned int level )
4181 {
4182 if( !src || !f || !fmt ) return cson_rc.ArgError;
4183 else if( ! cson_value_is_object(src) ) return cson_rc.TypeError;
4184 else if( level > fmt->maxDepth ) return cson_rc.RangeError;
4185 else
4186 {
4187 int rc;
4188 unsigned int i;
4189 cson_kvp const * kvp;
@@ -4267,17 +4265,17 @@
4267 return rc;
4268 }
4269
4270 int cson_data_dest_FILE( void * state, void const * src, unsigned int n )
4271 {
4272 if( ! state ) return cson_rc.ArgError;
4273 else if( !src || !n ) return 0;
4274 else
4275 {
4276 return ( 1 == fwrite( src, n, 1, (FILE*) state ) )
4277 ? 0
4278 : cson_rc.IOError;
4279 }
4280 }
4281
4282 int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * fmt )
4283 {
@@ -4300,15 +4298,15 @@
4300 return rc;
4301 }
4302
4303 int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt )
4304 {
4305 if( !src || !dest ) return cson_rc.ArgError;
4306 else
4307 {
4308 FILE * f = fopen(dest,"wb");
4309 if( !f ) return cson_rc.IOError;
4310 else
4311 {
4312 int const rc = cson_output_FILE( src, f, fmt );
4313 fclose(f);
4314 return rc;
@@ -4317,15 +4315,15 @@
4317 }
4318
4319 int cson_parse_filename( cson_value ** tgt, char const * src,
4320 cson_parse_opt const * opt, cson_parse_info * err )
4321 {
4322 if( !src || !tgt ) return cson_rc.ArgError;
4323 else
4324 {
4325 FILE * f = fopen(src, "r");
4326 if( !f ) return cson_rc.IOError;
4327 else
4328 {
4329 int const rc = cson_parse_FILE( tgt, f, opt, err );
4330 fclose(f);
4331 return rc;
@@ -4349,11 +4347,11 @@
4349 A cson_data_source_f() implementation which requires the state argument
4350 to be a properly populated (cson_data_source_StringSource_t*).
4351 */
4352 static int cson_data_source_StringSource( void * state, void * dest, unsigned int * n )
4353 {
4354 if( !state || !n || !dest ) return cson_rc.ArgError;
4355 else if( !*n ) return 0 /* ignore this */;
4356 else
4357 {
4358 unsigned int i;
4359 cson_data_source_StringSource_t * ss = (cson_data_source_StringSource_t*) state;
@@ -4368,12 +4366,12 @@
4368 }
4369
4370 int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
4371 cson_parse_opt const * opt, cson_parse_info * err )
4372 {
4373 if( ! tgt || !src ) return cson_rc.ArgError;
4374 else if( !*src || (len<2/*2==len of {} and []*/) ) return cson_rc.RangeError;
4375 else
4376 {
4377 cson_data_source_StringSource_t ss;
4378 ss.str = ss.pos = src;
4379 ss.end = src + len;
@@ -4386,18 +4384,18 @@
4386 cson_buffer const * buf,
4387 cson_parse_opt const * opt,
4388 cson_parse_info * err )
4389 {
4390 return ( !tgt || !buf || !buf->mem || !buf->used )
4391 ? cson_rc.ArgError
4392 : cson_parse_string( tgt, (char const *)buf->mem,
4393 buf->used, opt, err );
4394 }
4395
4396 int cson_buffer_reserve( cson_buffer * buf, cson_size_t n )
4397 {
4398 if( ! buf ) return cson_rc.ArgError;
4399 else if( 0 == n )
4400 {
4401 cson_free(buf->mem, "cson_buffer::mem");
4402 *buf = cson_buffer_empty;
4403 return 0;
@@ -4407,11 +4405,11 @@
4407 return 0;
4408 }
4409 else
4410 {
4411 unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" );
4412 if( ! x ) return cson_rc.AllocError;
4413 memset( x + buf->used, 0, n - buf->used );
4414 buf->mem = x;
4415 buf->capacity = n;
4416 ++buf->timesExpanded;
4417 return 0;
@@ -4434,11 +4432,11 @@
4434 arg MUST be a (cson_buffer*). This function appends n bytes at
4435 position arg->used, expanding the buffer as necessary.
4436 */
4437 static int cson_data_dest_cson_buffer( void * arg, void const * data_, unsigned int n )
4438 {
4439 if( !arg ) return cson_rc.ArgError;
4440 else if( ! n ) return 0;
4441 else
4442 {
4443 cson_buffer * sb = (cson_buffer*)arg;
4444 char const * data = (char const *)data_;
@@ -4446,12 +4444,12 @@
4446 unsigned int i;
4447 if( npos >= sb->capacity )
4448 {
4449 const cson_size_t oldCap = sb->capacity;
4450 const cson_size_t asz = npos * 2;
4451 if( asz < npos ) return cson_rc.ArgError; /* overflow */
4452 else if( 0 != cson_buffer_reserve( sb, asz ) ) return cson_rc.AllocError;
4453 assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
4454 /* make sure it gets NUL terminated. */
4455 memset( sb->mem + oldCap, 0, (sb->capacity - oldCap) );
4456 }
4457 for( i = 0; i < n; ++i, ++sb->used )
@@ -4533,19 +4531,19 @@
4533 return (pos > *inp) ? 1 : 0;
4534 }
4535
4536 int cson_object_fetch_sub2( cson_object const * obj, cson_value ** tgt, char const * path )
4537 {
4538 if( ! obj || !path ) return cson_rc.ArgError;
4539 else if( !*path || !*(1+path) ) return cson_rc.RangeError;
4540 else return cson_object_fetch_sub(obj, tgt, path+1, *path);
4541 }
4542
4543 int cson_object_fetch_sub( cson_object const * obj, cson_value ** tgt, char const * path, char sep )
4544 {
4545 if( ! obj || !path ) return cson_rc.ArgError;
4546 else if( !*path || !sep ) return cson_rc.RangeError;
4547 else
4548 {
4549 char const * beg = path;
4550 char const * end = NULL;
4551 int rc;
@@ -4565,26 +4563,26 @@
4565 ++tokenCount;
4566 beg = end;
4567 end = NULL;
4568 }
4569 }
4570 if( 0 == tokenCount ) return cson_rc.RangeError;
4571 beg = path;
4572 end = NULL;
4573 for( i = 0; i < tokenCount; ++i, beg=end, end=NULL )
4574 {
4575 rc = cson_next_token( &beg, sep, &end );
4576 assert( 1 == rc );
4577 assert( beg != end );
4578 assert( end > beg );
4579 len = end - beg;
4580 if( len > (BufSize-1) ) return cson_rc.RangeError;
4581 memset( buf, 0, len + 1 );
4582 memcpy( buf, beg, len );
4583 buf[len] = 0;
4584 cv = cson_object_get( curObj, buf );
4585 if( NULL == cv ) return cson_rc.NotFoundError;
4586 else if( i == (tokenCount-1) )
4587 {
4588 if(tgt) *tgt = cv;
4589 return 0;
4590 }
@@ -4594,15 +4592,15 @@
4594 assert((NULL != curObj) && "Detected mis-management of internal memory!");
4595 }
4596 /* TODO: arrays. Requires numeric parsing for the index. */
4597 else
4598 {
4599 return cson_rc.NotFoundError;
4600 }
4601 }
4602 assert( i == tokenCount );
4603 return cson_rc.NotFoundError;
4604 }
4605 }
4606
4607 cson_value * cson_object_get_sub( cson_object const * obj, char const * path, char sep )
4608 {
@@ -4838,24 +4836,26 @@
4838 }
4839 case CSON_TYPE_STRING: {
4840 cson_string const * jstr = cson_value_get_string(orig);
4841 unsigned const int slen = cson_string_length_bytes( jstr );
4842 assert( NULL != jstr );
4843 v = cson_strdup( cson_string_cstr( jstr ), slen );
4844 break;
4845 }
4846 case CSON_TYPE_INTEGER: {
4847 char buf[BufSize] = {0};
4848 if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) )
 
4849 {
4850 v = cson_strdup( buf, strlen(buf) );
4851 }
4852 break;
4853 }
4854 case CSON_TYPE_DOUBLE: {
4855 char buf[BufSize] = {0};
4856 if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) )
 
4857 {
4858 v = cson_strdup( buf, strlen(buf) );
4859 }
4860 break;
4861 }
@@ -4891,24 +4891,26 @@
4891 }
4892 case CSON_TYPE_STRING: {
4893 cson_string const * jstr = cson_value_get_string(orig);
4894 unsigned const int slen = cson_string_length_bytes( jstr );
4895 assert( NULL != jstr );
4896 v = cson_strdup( cson_string_cstr( jstr ), slen );
4897 break;
4898 }
4899 case CSON_TYPE_INTEGER: {
4900 char buf[BufSize] = {0};
4901 if( 0 < sprintf( v, "%"CSON_INT_T_PFMT, cson_value_get_integer(orig)) )
 
4902 {
4903 v = cson_strdup( buf, strlen(buf) );
4904 }
4905 break;
4906 }
4907 case CSON_TYPE_DOUBLE: {
4908 char buf[BufSize] = {0};
4909 if( 0 < sprintf( v, "%"CSON_DOUBLE_T_PFMT, cson_value_get_double(orig)) )
 
4910 {
4911 v = cson_strdup( buf, strlen(buf) );
4912 }
4913 break;
4914 }
@@ -4988,11 +4990,11 @@
4988 cson_object_iterator iter = cson_object_iterator_empty;
4989 int rc;
4990 char const replace = (flags & CSON_MERGE_REPLACE);
4991 char const recurse = !(flags & CSON_MERGE_NO_RECURSE);
4992 cson_kvp const * kvp;
4993 if((!dest || !src) || (dest==src)) return cson_rc.ArgError;
4994 rc = cson_object_iter_init( src, &iter );
4995 if(rc) return rc;
4996 while( (kvp = cson_object_iter_next(&iter) ) )
4997 {
4998 cson_string * key = cson_kvp_key(kvp);
@@ -5052,11 +5054,11 @@
5052 int cson_parse_argv_flags( int argc, char const * const * argv,
5053 cson_object ** tgt, unsigned int * count ){
5054 cson_object * o = NULL;
5055 int rc = 0;
5056 int i = 0;
5057 if(argc<1 || !argc || !tgt) return cson_rc.ArgError;
5058 o = *tgt ? *tgt : cson_new_object();
5059 if(count) *count = 0;
5060 for( i = 0; i < argc; ++i ){
5061 char const * arg = argv[i];
5062 char const * key = arg;
@@ -5068,11 +5070,11 @@
5068 if(!*key) continue;
5069 pos = key;
5070 while( *pos && ('=' != *pos)) ++pos;
5071 k = cson_new_string(key, pos-key);
5072 if(!k){
5073 rc = cson_rc.AllocError;
5074 break;
5075 }
5076 if(!*pos){ /** --key */
5077 v = cson_value_true();
5078 }else{ /** --key=...*/
@@ -5389,11 +5391,11 @@
5389 cson_string * colName = NULL;
5390 int i = 0;
5391 int rc = 0;
5392 cson_value * currentValue = NULL;
5393 int const colCount = sqlite3_column_count(st);
5394 if( !colCount || (colCount>(int)cson_array_length_get(colNames)) ) {
5395 return NULL;
5396 }
5397 rootV = cson_value_new_object();
5398 if(!rootV) return NULL;
5399 root = cson_value_get_object(rootV);
5400
--- extsrc/cson_amalgamation.c
+++ extsrc/cson_amalgamation.c
@@ -1435,11 +1435,10 @@
1435 #if defined(__cplusplus)
1436 extern "C" {
1437 #endif
1438
1439
 
1440 /**
1441 This type holds the "vtbl" for type-specific operations when
1442 working with cson_value objects.
1443
1444 All cson_values of a given logical type share a pointer to a single
@@ -1686,12 +1685,12 @@
1685 : 0;
1686 }
1687
1688 char const * cson_rc_string(int rc)
1689 {
1690 switch(rc){
1691 #define CHECK(N) case CSON_RC_##N: return #N;
1692 CHECK(OK);
1693 CHECK(ArgError);
1694 CHECK(RangeError);
1695 CHECK(TypeError);
1696 CHECK(IOError);
@@ -1708,11 +1707,12 @@
1707 CHECK(Parse_INVALID_NUMBER);
1708 CHECK(Parse_NESTING_DEPTH_REACHED);
1709 CHECK(Parse_UNBALANCED_COLLECTION);
1710 CHECK(Parse_EXPECTED_KEY);
1711 CHECK(Parse_EXPECTED_COLON);
1712 default: return "UnknownError";
1713 }
1714 #undef CHECK
1715 }
1716
1717 /**
1718 If CSON_LOG_ALLOC is true then the cson_malloc/realloc/free() routines
@@ -1854,11 +1854,11 @@
1854 }
1855
1856 #if 0
1857 int cson_value_refcount_set( cson_value * cv, unsigned short rc )
1858 {
1859 if( NULL == cv ) return CSON_RC_ArgError;
1860 else
1861 {
1862 cv->refcount = rc;
1863 return 0;
1864 }
@@ -1865,14 +1865,14 @@
1865 }
1866 #endif
1867
1868 int cson_value_add_reference( cson_value * cv )
1869 {
1870 if( NULL == cv ) return CSON_RC_ArgError;
1871 else if( (cv->refcount+1) < cv->refcount )
1872 {
1873 return CSON_RC_RangeError;
1874 }
1875 else
1876 {
1877 cson_refcount_incr( cv );
1878 return 0;
@@ -2335,11 +2335,11 @@
2335 val->refcount = rc;
2336 }
2337 }
2338 }
2339
2340 static cson_value * cson_value_array_alloc(void)
2341 {
2342 cson_value * v = cson_value_new(CSON_TYPE_ARRAY,0);
2343 if( NULL != v )
2344 {
2345 cson_array * ar = CSON_ARRAY(v);
@@ -2347,11 +2347,11 @@
2347 *ar = cson_array_empty;
2348 }
2349 return v;
2350 }
2351
2352 static cson_value * cson_value_object_alloc(void)
2353 {
2354 cson_value * v = cson_value_new(CSON_TYPE_OBJECT,0);
2355 if( NULL != v )
2356 {
2357 cson_object * obj = CSON_OBJ(v);
@@ -2359,28 +2359,28 @@
2359 *obj = cson_object_empty;
2360 }
2361 return v;
2362 }
2363
2364 cson_value * cson_value_new_object(void)
2365 {
2366 return cson_value_object_alloc();
2367 }
2368
2369 cson_object * cson_new_object(void)
2370 {
2371
2372 return cson_value_get_object( cson_value_new_object() );
2373 }
2374
2375 cson_value * cson_value_new_array(void)
2376 {
2377 return cson_value_array_alloc();
2378 }
2379
2380
2381 cson_array * cson_new_array(void)
2382 {
2383 return cson_value_get_array( cson_value_new_array() );
2384 }
2385
2386 /**
@@ -2502,11 +2502,11 @@
2502 int rc;
2503 enum { BufSize = 1024 * 4 };
2504 char rbuf[BufSize];
2505 size_t total = 0;
2506 unsigned int rlen = 0;
2507 if( ! dest || ! src ) return CSON_RC_ArgError;
2508 dest->used = 0;
2509 while(1)
2510 {
2511 rlen = BufSize;
2512 rc = src( state, rbuf, &rlen );
@@ -2530,16 +2530,16 @@
2530 }
2531
2532 int cson_data_source_FILE( void * state, void * dest, unsigned int * n )
2533 {
2534 FILE * f = (FILE*) state;
2535 if( ! state || ! n || !dest ) return CSON_RC_ArgError;
2536 else if( !*n ) return CSON_RC_RangeError;
2537 *n = (unsigned int)fread( dest, 1, *n, f );
2538 if( !*n )
2539 {
2540 return feof(f) ? 0 : CSON_RC_IOError;
2541 }
2542 return 0;
2543 }
2544
2545 int cson_parse_FILE( cson_value ** tgt, FILE * src,
@@ -2553,11 +2553,11 @@
2553 {
2554 /**
2555 FIXME: move the to-bool operation into cson_value_api, like we
2556 do in the C++ API.
2557 */
2558 if( ! val || !val->api ) return CSON_RC_ArgError;
2559 else
2560 {
2561 int rc = 0;
2562 char b = 0;
2563 switch( val->api->typeID )
@@ -2588,11 +2588,11 @@
2588 cson_value_fetch_double( val, &d );
2589 b = (0.0==d) ? 0 : 1;
2590 break;
2591 }
2592 default:
2593 rc = CSON_RC_TypeError;
2594 break;
2595 }
2596 if( v ) *v = b;
2597 return rc;
2598 }
@@ -2605,11 +2605,11 @@
2605 return i;
2606 }
2607
2608 int cson_value_fetch_integer( cson_value const * val, cson_int_t * v )
2609 {
2610 if( ! val || !val->api ) return CSON_RC_ArgError;
2611 else
2612 {
2613 cson_int_t i = 0;
2614 int rc = 0;
2615 switch(val->api->typeID)
@@ -2641,11 +2641,11 @@
2641 }
2642 case CSON_TYPE_STRING:
2643 case CSON_TYPE_ARRAY:
2644 case CSON_TYPE_OBJECT:
2645 default:
2646 rc = CSON_RC_TypeError;
2647 break;
2648 }
2649 if(!rc && v) *v = i;
2650 return rc;
2651 }
@@ -2658,11 +2658,11 @@
2658 return i;
2659 }
2660
2661 int cson_value_fetch_double( cson_value const * val, cson_double_t * v )
2662 {
2663 if( ! val || !val->api ) return CSON_RC_ArgError;
2664 else
2665 {
2666 cson_double_t d = 0.0;
2667 int rc = 0;
2668 switch(val->api->typeID)
@@ -2687,11 +2687,11 @@
2687 cson_double_t const* dv = CSON_DBL(val);
2688 d = dv ? *dv : 0.0;
2689 break;
2690 }
2691 default:
2692 rc = CSON_RC_TypeError;
2693 break;
2694 }
2695 if(v) *v = d;
2696 return rc;
2697 }
@@ -2704,12 +2704,12 @@
2704 return i;
2705 }
2706
2707 int cson_value_fetch_string( cson_value const * val, cson_string ** dest )
2708 {
2709 if( ! val || ! dest ) return CSON_RC_ArgError;
2710 else if( ! cson_value_is_string(val) ) return CSON_RC_TypeError;
2711 else
2712 {
2713 if( dest ) *dest = CSON_STR(val);
2714 return 0;
2715 }
@@ -2727,12 +2727,12 @@
2727 return cson_string_cstr( cson_value_get_string(val) );
2728 }
2729
2730 int cson_value_fetch_object( cson_value const * val, cson_object ** obj )
2731 {
2732 if( ! val ) return CSON_RC_ArgError;
2733 else if( ! cson_value_is_object(val) ) return CSON_RC_TypeError;
2734 else
2735 {
2736 if(obj) *obj = CSON_OBJ(val);
2737 return 0;
2738 }
@@ -2744,12 +2744,12 @@
2744 return obj;
2745 }
2746
2747 int cson_value_fetch_array( cson_value const * val, cson_array ** ar)
2748 {
2749 if( ! val ) return CSON_RC_ArgError;
2750 else if( !cson_value_is_array(val) ) return CSON_RC_TypeError;
2751 else
2752 {
2753 if(ar) *ar = CSON_ARRAY(val);
2754 return 0;
2755 }
@@ -2760,11 +2760,11 @@
2760 cson_array * ar = NULL;
2761 cson_value_fetch_array( v, &ar );
2762 return ar;
2763 }
2764
2765 cson_kvp * cson_kvp_alloc(void)
2766 {
2767 cson_kvp * kvp = (cson_kvp*)cson_malloc(sizeof(cson_kvp),"cson_kvp");
2768 if( kvp )
2769 {
2770 *kvp = cson_kvp_empty;
@@ -2774,20 +2774,20 @@
2774
2775
2776
2777 int cson_array_append( cson_array * ar, cson_value * v )
2778 {
2779 if( !ar || !v ) return CSON_RC_ArgError;
2780 else if( (ar->list.count+1) < ar->list.count ) return CSON_RC_RangeError;
2781 else
2782 {
2783 if( !ar->list.alloced || (ar->list.count == ar->list.alloced-1))
2784 {
2785 unsigned int const n = ar->list.count ? (ar->list.count*2) : 7;
2786 if( n > cson_value_list_reserve( &ar->list, n ) )
2787 {
2788 return CSON_RC_AllocError;
2789 }
2790 }
2791 return cson_array_set( ar, ar->list.count, v );
2792 }
2793 }
@@ -2832,20 +2832,20 @@
2832 cson_value * cson_value_new_bool( char v )
2833 {
2834 return v ? &CSON_SPECIAL_VALUES[CSON_VAL_TRUE] : &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
2835 }
2836
2837 cson_value * cson_value_true(void)
2838 {
2839 return &CSON_SPECIAL_VALUES[CSON_VAL_TRUE];
2840 }
2841 cson_value * cson_value_false(void)
2842 {
2843 return &CSON_SPECIAL_VALUES[CSON_VAL_FALSE];
2844 }
2845
2846 cson_value * cson_value_null(void)
2847 {
2848 return &CSON_SPECIAL_VALUES[CSON_VAL_NULL];
2849 }
2850
2851 cson_value * cson_new_int( cson_int_t v )
@@ -2917,12 +2917,12 @@
2917 return cson_string_value( cson_new_string(str, len) );
2918 }
2919
2920 int cson_array_value_fetch( cson_array const * ar, unsigned int pos, cson_value ** v )
2921 {
2922 if( !ar) return CSON_RC_ArgError;
2923 if( pos >= ar->list.count ) return CSON_RC_RangeError;
2924 else
2925 {
2926 if(v) *v = ar->list.list[pos];
2927 return 0;
2928 }
@@ -2935,11 +2935,11 @@
2935 return v;
2936 }
2937
2938 int cson_array_length_fetch( cson_array const * ar, unsigned int * v )
2939 {
2940 if( ! ar || !v ) return CSON_RC_ArgError;
2941 else
2942 {
2943 if(v) *v = ar->list.count;
2944 return 0;
2945 }
@@ -2952,11 +2952,11 @@
2952 return i;
2953 }
2954
2955 int cson_array_reserve( cson_array * ar, unsigned int size )
2956 {
2957 if( ! ar ) return CSON_RC_ArgError;
2958 else if( size <= ar->list.alloced )
2959 {
2960 /* We don't want to introduce a can of worms by trying to
2961 handle the cleanup from here.
2962 */
@@ -2963,24 +2963,24 @@
2963 return 0;
2964 }
2965 else
2966 {
2967 return (ar->list.alloced > cson_value_list_reserve( &ar->list, size ))
2968 ? CSON_RC_AllocError
2969 : 0
2970 ;
2971 }
2972 }
2973
2974 int cson_array_set( cson_array * ar, unsigned int ndx, cson_value * v )
2975 {
2976 if( !ar || !v ) return CSON_RC_ArgError;
2977 else if( (ndx+1) < ndx) /* overflow */return CSON_RC_RangeError;
2978 else
2979 {
2980 unsigned const int len = cson_value_list_reserve( &ar->list, ndx+1 );
2981 if( len <= ndx ) return CSON_RC_AllocError;
2982 else
2983 {
2984 cson_value * old = ar->list.list[ndx];
2985 if( old )
2986 {
@@ -3076,18 +3076,18 @@
3076 }
3077 #endif
3078
3079 int cson_object_unset( cson_object * obj, char const * key )
3080 {
3081 if( ! obj || !key || !*key ) return CSON_RC_ArgError;
3082 else
3083 {
3084 unsigned int ndx = 0;
3085 cson_kvp * kvp = cson_object_search_impl( obj, key, &ndx );
3086 if( ! kvp )
3087 {
3088 return CSON_RC_NotFoundError;
3089 }
3090 assert( obj->kvp.count > 0 );
3091 assert( obj->kvp.list[ndx] == kvp );
3092 cson_kvp_free( kvp );
3093 obj->kvp.list[ndx] = NULL;
@@ -3109,21 +3109,21 @@
3109 }
3110 }
3111
3112 int cson_object_set_s( cson_object * obj, cson_string * key, cson_value * v )
3113 {
3114 if( !obj || !key ) return CSON_RC_ArgError;
3115 else if( NULL == v ) return cson_object_unset( obj, cson_string_cstr(key) );
3116 else
3117 {
3118 char const * cKey;
3119 cson_value * vKey;
3120 cson_kvp * kvp;
3121 vKey = cson_string_value(key);
3122 assert(vKey && (key==CSON_STR(vKey)));
3123 if( vKey == CSON_VCAST(obj) ){
3124 return CSON_RC_ArgError;
3125 }
3126 cKey = cson_string_cstr(key);
3127 kvp = cson_object_search_impl( obj, cKey, NULL );
3128 if( kvp )
3129 { /* "I told 'em we've already got one!" */
@@ -3142,19 +3142,19 @@
3142 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3143 { /* reserve space */
3144 unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
3145 if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
3146 {
3147 return CSON_RC_AllocError;
3148 }
3149 }
3150 { /* insert new item... */
3151 int rc = 0;
3152 kvp = cson_kvp_alloc();
3153 if( ! kvp )
3154 {
3155 return CSON_RC_AllocError;
3156 }
3157 rc = cson_kvp_list_append( &obj->kvp, kvp );
3158 if( 0 != rc )
3159 {
3160 cson_kvp_free(kvp);
@@ -3174,19 +3174,19 @@
3174 }
3175
3176 }
3177 int cson_object_set( cson_object * obj, char const * key, cson_value * v )
3178 {
3179 if( ! obj || !key || !*key ) return CSON_RC_ArgError;
3180 else if( NULL == v )
3181 {
3182 return cson_object_unset( obj, key );
3183 }
3184 else
3185 {
3186 cson_string * cs = cson_new_string(key,strlen(key));
3187 if(!cs) return CSON_RC_AllocError;
3188 else
3189 {
3190 int const rc = cson_object_set_s(obj, cs, v);
3191 if(rc) cson_value_free(cson_string_value(cs));
3192 return rc;
@@ -3237,13 +3237,13 @@
3237 }
3238 }
3239 /** @internal
3240
3241 If p->node is-a Object then value is inserted into the object
3242 using p->key. In any other case CSON_RC_InternalError is returned.
3243
3244 Returns CSON_RC_AllocError if an allocation fails.
3245
3246 Returns 0 on success. On error, parsing must be ceased immediately.
3247
3248 Ownership of val is ALWAYS TRANSFERED to this function. If this
3249 function fails, val will be cleaned up and destroyed. (This
@@ -3267,18 +3267,18 @@
3267 if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
3268 {
3269 if( obj->kvp.alloced > cson_kvp_list_reserve( &obj->kvp, obj->kvp.count ? (obj->kvp.count*2) : 5 ) )
3270 {
3271 cson_value_free(val);
3272 return CSON_RC_AllocError;
3273 }
3274 }
3275 kvp = cson_kvp_alloc();
3276 if( ! kvp )
3277 {
3278 cson_value_free(val);
3279 return CSON_RC_AllocError;
3280 }
3281 kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
3282 assert(0 == kvp->key->refcount);
3283 cson_refcount_incr(kvp->key);
3284 p->ckey = NULL;
@@ -3296,11 +3296,11 @@
3296 return rc;
3297 }
3298 else
3299 {
3300 if(val) cson_value_free(val);
3301 return p->errNo = CSON_RC_InternalError;
3302 }
3303
3304 }
3305
3306 /** @internal
@@ -3337,11 +3337,11 @@
3337 return rc;
3338 }
3339 else
3340 { /* WTF? */
3341 assert( 0 && "Internal error in cson_parser code" );
3342 return p->errNo = CSON_RC_InternalError;
3343 }
3344 }
3345
3346 /**
3347 Callback for JSON_parser API. Reminder: it returns 0 (meaning false)
@@ -3349,20 +3349,20 @@
3349 */
3350 static int cson_parse_callback( void * cx, int type, JSON_value const * value )
3351 {
3352 cson_parser * p = (cson_parser *)cx;
3353 int rc = 0;
3354 #define ALLOC_V(T,V) cson_value * v = cson_value_new_##T(V); if( ! v ) { rc = CSON_RC_AllocError; break; }
3355 switch(type) {
3356 case JSON_T_ARRAY_BEGIN:
3357 case JSON_T_OBJECT_BEGIN: {
3358 cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
3359 ? cson_value_new_array()
3360 : cson_value_new_object();
3361 if( ! obja )
3362 {
3363 p->errNo = CSON_RC_AllocError;
3364 break;
3365 }
3366 if( 0 != rc ) break;
3367 if( ! p->root )
3368 {
@@ -3395,11 +3395,11 @@
3395 }
3396 case JSON_T_ARRAY_END:
3397 case JSON_T_OBJECT_END: {
3398 if( 0 == p->stack.list.count )
3399 {
3400 rc = CSON_RC_RangeError;
3401 break;
3402 }
3403 #if CSON_OBJECT_PROPS_SORT
3404 if( cson_value_is_object(p->node) )
3405 {/* kludge: the parser uses custom cson_object property
@@ -3481,26 +3481,26 @@
3481 case JSON_T_KEY: {
3482 assert(!p->ckey);
3483 p->ckey = cson_new_string( value->vu.str.value, value->vu.str.length );
3484 if( ! p->ckey )
3485 {
3486 rc = CSON_RC_AllocError;
3487 break;
3488 }
3489 ++p->totalKeyCount;
3490 break;
3491 }
3492 case JSON_T_STRING: {
3493 cson_value * v = cson_value_new_string( value->vu.str.value, value->vu.str.length );
3494 rc = ( NULL == v )
3495 ? CSON_RC_AllocError
3496 : cson_parser_push_value( p, v );
3497 break;
3498 }
3499 default:
3500 assert(0);
3501 rc = CSON_RC_InternalError;
3502 break;
3503 }
3504 #undef ALLOC_V
3505 return ((p->errNo = rc)) ? 0 : 1;
3506 }
@@ -3512,22 +3512,22 @@
3512 static int cson_json_err_to_rc( JSON_error jrc )
3513 {
3514 switch(jrc)
3515 {
3516 case JSON_E_NONE: return 0;
3517 case JSON_E_INVALID_CHAR: return CSON_RC_Parse_INVALID_CHAR;
3518 case JSON_E_INVALID_KEYWORD: return CSON_RC_Parse_INVALID_KEYWORD;
3519 case JSON_E_INVALID_ESCAPE_SEQUENCE: return CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE;
3520 case JSON_E_INVALID_UNICODE_SEQUENCE: return CSON_RC_Parse_INVALID_UNICODE_SEQUENCE;
3521 case JSON_E_INVALID_NUMBER: return CSON_RC_Parse_INVALID_NUMBER;
3522 case JSON_E_NESTING_DEPTH_REACHED: return CSON_RC_Parse_NESTING_DEPTH_REACHED;
3523 case JSON_E_UNBALANCED_COLLECTION: return CSON_RC_Parse_UNBALANCED_COLLECTION;
3524 case JSON_E_EXPECTED_KEY: return CSON_RC_Parse_EXPECTED_KEY;
3525 case JSON_E_EXPECTED_COLON: return CSON_RC_Parse_EXPECTED_COLON;
3526 case JSON_E_OUT_OF_MEMORY: return CSON_RC_AllocError;
3527 default:
3528 return CSON_RC_InternalError;
3529 }
3530 }
3531
3532 /** @internal
3533
@@ -3543,11 +3543,11 @@
3543 any other items inserted into it (or under it) during the parsing
3544 process.
3545 */
3546 static int cson_parser_clean( cson_parser * p )
3547 {
3548 if( ! p ) return CSON_RC_ArgError;
3549 else
3550 {
3551 if( p->p )
3552 {
3553 delete_JSON_parser(p->p);
@@ -3574,11 +3574,11 @@
3574 cson_parse_opt const opt = opt_ ? *opt_ : cson_parse_opt_empty;
3575 int rc = 0;
3576 unsigned int len = 1;
3577 cson_parse_info info = info_ ? *info_ : cson_parse_info_empty;
3578 cson_parser p = cson_parser_empty;
3579 if( ! tgt || ! src ) return CSON_RC_ArgError;
3580
3581 {
3582 JSON_config jopt = {0};
3583 init_JSON_config( &jopt );
3584 jopt.allow_comments = opt.allowComments;
@@ -3587,11 +3587,11 @@
3587 jopt.handle_floats_manually = 0;
3588 jopt.callback = cson_parse_callback;
3589 p.p = new_JSON_parser(&jopt);
3590 if( ! p.p )
3591 {
3592 return CSON_RC_AllocError;
3593 }
3594 }
3595
3596 do
3597 { /* FIXME: buffer the input in multi-kb chunks. */
@@ -3608,11 +3608,11 @@
3608 }
3609 if( ! JSON_parser_char(p.p, ch[0]) )
3610 {
3611 rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
3612 if(0==rc) rc = p.errNo;
3613 if(0==rc) rc = CSON_RC_InternalError;
3614 info.errorCode = rc;
3615 break;
3616 }
3617 if( '\n' != ch[0]) ++info.col;
3618 } while(1);
@@ -3630,11 +3630,11 @@
3630 if( ! JSON_parser_done(p.p) )
3631 {
3632 rc = cson_json_err_to_rc( JSON_parser_get_last_error(p.p) );
3633 cson_parser_clean(&p);
3634 if(0==rc) rc = p.errNo;
3635 if(0==rc) rc = CSON_RC_InternalError;
3636 }
3637 else
3638 {
3639 cson_value * root = p.root;
3640 p.root = NULL;
@@ -3652,11 +3652,11 @@
3652 */;
3653 *tgt = root;
3654 }
3655 else
3656 { /* then can happen on empty input. */
3657 rc = CSON_RC_UnknownError;
3658 }
3659 }
3660 return rc;
3661 }
3662
@@ -3771,11 +3771,11 @@
3771 */
3772 static int cson_str_to_json( char const * str, unsigned int len,
3773 char escapeFwdSlash,
3774 cson_data_dest_f f, void * state )
3775 {
3776 if( NULL == f ) return CSON_RC_ArgError;
3777 else if( !str || !*str || (0 == len) )
3778 { /* special case for 0-length strings. */
3779 return f( state, "\"\"", 2 );
3780 }
3781 else
@@ -3877,26 +3877,26 @@
3877 #if defined(CSON_FOSSIL_MODE)
3878 assume_latin1:
3879 #endif
3880 memset(ubuf,0,UBLen);
3881 if(ch <= 0xFFFF){
3882 rc = snprintf(ubuf, (size_t)UBLen, "\\u%04x",ch);
3883 if( rc != 6 )
3884 {
3885 rc = CSON_RC_RangeError;
3886 break;
3887 }
3888 rc = f( state, ubuf, 6 );
3889 }else{ /* encode as a UTF16 surrogate pair */
3890 /* http://unicodebook.readthedocs.org/en/latest/unicode_encodings.html#surrogates */
3891 ch -= 0x10000;
3892 rc = snprintf(ubuf, (size_t)UBLen, "\\u%04x\\u%04x",
3893 (0xd800 | (ch>>10)),
3894 (0xdc00 | (ch & 0x3ff)));
3895 if( rc != 12 )
3896 {
3897 rc = CSON_RC_RangeError;
3898 break;
3899 }
3900 rc = f( state, ubuf, 12 );
3901 }
3902 continue;
@@ -3910,11 +3910,11 @@
3910 }
3911 }
3912
3913 int cson_object_iter_init( cson_object const * obj, cson_object_iterator * iter )
3914 {
3915 if( ! obj || !iter ) return CSON_RC_ArgError;
3916 else
3917 {
3918 iter->obj = obj;
3919 iter->pos = 0;
3920 return 0;
@@ -3936,64 +3936,62 @@
3936 }
3937 }
3938
3939 static int cson_output_null( cson_data_dest_f f, void * state )
3940 {
3941 if( !f ) return CSON_RC_ArgError;
3942 else
3943 {
3944 return f(state, "null", 4);
3945 }
3946 }
3947
3948 static int cson_output_bool( cson_value const * src, cson_data_dest_f f, void * state )
3949 {
3950 if( !f ) return CSON_RC_ArgError;
3951 else
3952 {
3953 char const v = cson_value_get_bool(src);
3954 return f(state, v ? "true" : "false", v ? 4 : 5);
3955 }
3956 }
3957
3958 static int cson_output_integer( cson_value const * src, cson_data_dest_f f, void * state )
3959 {
3960 if( !f ) return CSON_RC_ArgError;
3961 else if( !cson_value_is_integer(src) ) return CSON_RC_TypeError;
3962 else
3963 {
3964 enum { BufLen = 100 };
3965 char b[BufLen];
3966 int rc;
3967 memset( b, 0, BufLen );
3968 rc = snprintf( b, (size_t)BufLen, "%"CSON_INT_T_PFMT,
3969 cson_value_get_integer(src) );
 
3970 return ( rc<=0 )
3971 ? CSON_RC_RangeError
3972 : f( state, b, (unsigned int)rc )
3973 ;
3974 }
3975 }
3976
3977 static int cson_output_double( cson_value const * src, cson_data_dest_f f, void * state )
3978 {
3979 if( !f ) return CSON_RC_ArgError;
3980 else if( !cson_value_is_double(src) ) return CSON_RC_TypeError;
3981 else
3982 {
3983 enum { BufLen = 128 /* this must be relatively large or huge
3984 doubles can cause us to overrun here,
3985 resulting in stack-smashing errors.
3986 */};
3987 char b[BufLen];
3988 int rc;
3989 memset( b, 0, BufLen );
3990 rc = snprintf( b, (size_t)BufLen, "%"CSON_DOUBLE_T_PFMT,
3991 cson_value_get_double(src) );
3992 if( rc<=0 ) return CSON_RC_RangeError;
 
3993 else if(1)
3994 { /* Strip trailing zeroes before passing it on... */
3995 unsigned int urc = (unsigned int)rc;
3996 char * pos = b + urc - 1;
3997 for( ; ('0' == *pos) && urc && (*(pos-1) != '.'); --pos, --urc )
@@ -4012,12 +4010,12 @@
4010 }
4011 }
4012
4013 static int cson_output_string( cson_value const * src, char escapeFwdSlash, cson_data_dest_f f, void * state )
4014 {
4015 if( !f ) return CSON_RC_ArgError;
4016 else if( ! cson_value_is_string(src) ) return CSON_RC_TypeError;
4017 else
4018 {
4019 cson_string const * str = cson_value_get_string(src);
4020 assert( NULL != str );
4021 return cson_str_to_json(cson_string_cstr(str), str->length, escapeFwdSlash, f, state);
@@ -4075,11 +4073,11 @@
4073 Returns 0 on success.
4074 */
4075 static int cson_output_impl( cson_value const * src, cson_data_dest_f f, void * state,
4076 cson_output_opt const * fmt, unsigned int level )
4077 {
4078 if( ! src || !f || !src->api ) return CSON_RC_ArgError;
4079 else
4080 {
4081 int rc = 0;
4082 assert(fmt);
4083 switch( src->api->typeID )
@@ -4105,11 +4103,11 @@
4103 break;
4104 case CSON_TYPE_OBJECT:
4105 rc = cson_output_object( src, f, state, fmt, level );
4106 break;
4107 default:
4108 rc = CSON_RC_TypeError;
4109 break;
4110 }
4111 return rc;
4112 }
4113 }
@@ -4116,13 +4114,13 @@
4114
4115
4116 static int cson_output_array( cson_value const * src, cson_data_dest_f f, void * state,
4117 cson_output_opt const * fmt, unsigned int level )
4118 {
4119 if( !src || !f || !fmt ) return CSON_RC_ArgError;
4120 else if( ! cson_value_is_array(src) ) return CSON_RC_TypeError;
4121 else if( level > fmt->maxDepth ) return CSON_RC_RangeError;
4122 else
4123 {
4124 int rc;
4125 unsigned int i;
4126 cson_value const * v;
@@ -4177,13 +4175,13 @@
4175 }
4176
4177 static int cson_output_object( cson_value const * src, cson_data_dest_f f, void * state,
4178 cson_output_opt const * fmt, unsigned int level )
4179 {
4180 if( !src || !f || !fmt ) return CSON_RC_ArgError;
4181 else if( ! cson_value_is_object(src) ) return CSON_RC_TypeError;
4182 else if( level > fmt->maxDepth ) return CSON_RC_RangeError;
4183 else
4184 {
4185 int rc;
4186 unsigned int i;
4187 cson_kvp const * kvp;
@@ -4267,17 +4265,17 @@
4265 return rc;
4266 }
4267
4268 int cson_data_dest_FILE( void * state, void const * src, unsigned int n )
4269 {
4270 if( ! state ) return CSON_RC_ArgError;
4271 else if( !src || !n ) return 0;
4272 else
4273 {
4274 return ( 1 == fwrite( src, n, 1, (FILE*) state ) )
4275 ? 0
4276 : CSON_RC_IOError;
4277 }
4278 }
4279
4280 int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * fmt )
4281 {
@@ -4300,15 +4298,15 @@
4298 return rc;
4299 }
4300
4301 int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt )
4302 {
4303 if( !src || !dest ) return CSON_RC_ArgError;
4304 else
4305 {
4306 FILE * f = fopen(dest,"wb");
4307 if( !f ) return CSON_RC_IOError;
4308 else
4309 {
4310 int const rc = cson_output_FILE( src, f, fmt );
4311 fclose(f);
4312 return rc;
@@ -4317,15 +4315,15 @@
4315 }
4316
4317 int cson_parse_filename( cson_value ** tgt, char const * src,
4318 cson_parse_opt const * opt, cson_parse_info * err )
4319 {
4320 if( !src || !tgt ) return CSON_RC_ArgError;
4321 else
4322 {
4323 FILE * f = fopen(src, "r");
4324 if( !f ) return CSON_RC_IOError;
4325 else
4326 {
4327 int const rc = cson_parse_FILE( tgt, f, opt, err );
4328 fclose(f);
4329 return rc;
@@ -4349,11 +4347,11 @@
4347 A cson_data_source_f() implementation which requires the state argument
4348 to be a properly populated (cson_data_source_StringSource_t*).
4349 */
4350 static int cson_data_source_StringSource( void * state, void * dest, unsigned int * n )
4351 {
4352 if( !state || !n || !dest ) return CSON_RC_ArgError;
4353 else if( !*n ) return 0 /* ignore this */;
4354 else
4355 {
4356 unsigned int i;
4357 cson_data_source_StringSource_t * ss = (cson_data_source_StringSource_t*) state;
@@ -4368,12 +4366,12 @@
4366 }
4367
4368 int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
4369 cson_parse_opt const * opt, cson_parse_info * err )
4370 {
4371 if( ! tgt || !src ) return CSON_RC_ArgError;
4372 else if( !*src || (len<2/*2==len of {} and []*/) ) return CSON_RC_RangeError;
4373 else
4374 {
4375 cson_data_source_StringSource_t ss;
4376 ss.str = ss.pos = src;
4377 ss.end = src + len;
@@ -4386,18 +4384,18 @@
4384 cson_buffer const * buf,
4385 cson_parse_opt const * opt,
4386 cson_parse_info * err )
4387 {
4388 return ( !tgt || !buf || !buf->mem || !buf->used )
4389 ? CSON_RC_ArgError
4390 : cson_parse_string( tgt, (char const *)buf->mem,
4391 buf->used, opt, err );
4392 }
4393
4394 int cson_buffer_reserve( cson_buffer * buf, cson_size_t n )
4395 {
4396 if( ! buf ) return CSON_RC_ArgError;
4397 else if( 0 == n )
4398 {
4399 cson_free(buf->mem, "cson_buffer::mem");
4400 *buf = cson_buffer_empty;
4401 return 0;
@@ -4407,11 +4405,11 @@
4405 return 0;
4406 }
4407 else
4408 {
4409 unsigned char * x = (unsigned char *)cson_realloc( buf->mem, n, "cson_buffer::mem" );
4410 if( ! x ) return CSON_RC_AllocError;
4411 memset( x + buf->used, 0, n - buf->used );
4412 buf->mem = x;
4413 buf->capacity = n;
4414 ++buf->timesExpanded;
4415 return 0;
@@ -4434,11 +4432,11 @@
4432 arg MUST be a (cson_buffer*). This function appends n bytes at
4433 position arg->used, expanding the buffer as necessary.
4434 */
4435 static int cson_data_dest_cson_buffer( void * arg, void const * data_, unsigned int n )
4436 {
4437 if( !arg ) return CSON_RC_ArgError;
4438 else if( ! n ) return 0;
4439 else
4440 {
4441 cson_buffer * sb = (cson_buffer*)arg;
4442 char const * data = (char const *)data_;
@@ -4446,12 +4444,12 @@
4444 unsigned int i;
4445 if( npos >= sb->capacity )
4446 {
4447 const cson_size_t oldCap = sb->capacity;
4448 const cson_size_t asz = npos * 2;
4449 if( asz < npos ) return CSON_RC_ArgError; /* overflow */
4450 else if( 0 != cson_buffer_reserve( sb, asz ) ) return CSON_RC_AllocError;
4451 assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
4452 /* make sure it gets NUL terminated. */
4453 memset( sb->mem + oldCap, 0, (sb->capacity - oldCap) );
4454 }
4455 for( i = 0; i < n; ++i, ++sb->used )
@@ -4533,19 +4531,19 @@
4531 return (pos > *inp) ? 1 : 0;
4532 }
4533
4534 int cson_object_fetch_sub2( cson_object const * obj, cson_value ** tgt, char const * path )
4535 {
4536 if( ! obj || !path ) return CSON_RC_ArgError;
4537 else if( !*path || !*(1+path) ) return CSON_RC_RangeError;
4538 else return cson_object_fetch_sub(obj, tgt, path+1, *path);
4539 }
4540
4541 int cson_object_fetch_sub( cson_object const * obj, cson_value ** tgt, char const * path, char sep )
4542 {
4543 if( ! obj || !path ) return CSON_RC_ArgError;
4544 else if( !*path || !sep ) return CSON_RC_RangeError;
4545 else
4546 {
4547 char const * beg = path;
4548 char const * end = NULL;
4549 int rc;
@@ -4565,26 +4563,26 @@
4563 ++tokenCount;
4564 beg = end;
4565 end = NULL;
4566 }
4567 }
4568 if( 0 == tokenCount ) return CSON_RC_RangeError;
4569 beg = path;
4570 end = NULL;
4571 for( i = 0; i < tokenCount; ++i, beg=end, end=NULL )
4572 {
4573 rc = cson_next_token( &beg, sep, &end );
4574 assert( 1 == rc );
4575 assert( beg != end );
4576 assert( end > beg );
4577 len = end - beg;
4578 if( len > (BufSize-1) ) return CSON_RC_RangeError;
4579 memset( buf, 0, len + 1 );
4580 memcpy( buf, beg, len );
4581 buf[len] = 0;
4582 cv = cson_object_get( curObj, buf );
4583 if( NULL == cv ) return CSON_RC_NotFoundError;
4584 else if( i == (tokenCount-1) )
4585 {
4586 if(tgt) *tgt = cv;
4587 return 0;
4588 }
@@ -4594,15 +4592,15 @@
4592 assert((NULL != curObj) && "Detected mis-management of internal memory!");
4593 }
4594 /* TODO: arrays. Requires numeric parsing for the index. */
4595 else
4596 {
4597 return CSON_RC_NotFoundError;
4598 }
4599 }
4600 assert( i == tokenCount );
4601 return CSON_RC_NotFoundError;
4602 }
4603 }
4604
4605 cson_value * cson_object_get_sub( cson_object const * obj, char const * path, char sep )
4606 {
@@ -4838,24 +4836,26 @@
4836 }
4837 case CSON_TYPE_STRING: {
4838 cson_string const * jstr = cson_value_get_string(orig);
4839 unsigned const int slen = cson_string_length_bytes( jstr );
4840 assert( NULL != jstr );
4841 v = cson_strdup( cson_string_cstr( jstr ), slen );
4842 break;
4843 }
4844 case CSON_TYPE_INTEGER: {
4845 char buf[BufSize] = {0};
4846 if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_INT_T_PFMT,
4847 cson_value_get_integer(orig)) )
4848 {
4849 v = cson_strdup( buf, strlen(buf) );
4850 }
4851 break;
4852 }
4853 case CSON_TYPE_DOUBLE: {
4854 char buf[BufSize] = {0};
4855 if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_DOUBLE_T_PFMT,
4856 cson_value_get_double(orig)) )
4857 {
4858 v = cson_strdup( buf, strlen(buf) );
4859 }
4860 break;
4861 }
@@ -4891,24 +4891,26 @@
4891 }
4892 case CSON_TYPE_STRING: {
4893 cson_string const * jstr = cson_value_get_string(orig);
4894 unsigned const int slen = cson_string_length_bytes( jstr );
4895 assert( NULL != jstr );
4896 v = cson_strdup( cson_string_cstr( jstr ), slen );
4897 break;
4898 }
4899 case CSON_TYPE_INTEGER: {
4900 char buf[BufSize] = {0};
4901 if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_INT_T_PFMT,
4902 cson_value_get_integer(orig)) )
4903 {
4904 v = cson_strdup( buf, strlen(buf) );
4905 }
4906 break;
4907 }
4908 case CSON_TYPE_DOUBLE: {
4909 char buf[BufSize] = {0};
4910 if( 0 < snprintf( v, (size_t)BufSize, "%"CSON_DOUBLE_T_PFMT,
4911 cson_value_get_double(orig)) )
4912 {
4913 v = cson_strdup( buf, strlen(buf) );
4914 }
4915 break;
4916 }
@@ -4988,11 +4990,11 @@
4990 cson_object_iterator iter = cson_object_iterator_empty;
4991 int rc;
4992 char const replace = (flags & CSON_MERGE_REPLACE);
4993 char const recurse = !(flags & CSON_MERGE_NO_RECURSE);
4994 cson_kvp const * kvp;
4995 if((!dest || !src) || (dest==src)) return CSON_RC_ArgError;
4996 rc = cson_object_iter_init( src, &iter );
4997 if(rc) return rc;
4998 while( (kvp = cson_object_iter_next(&iter) ) )
4999 {
5000 cson_string * key = cson_kvp_key(kvp);
@@ -5052,11 +5054,11 @@
5054 int cson_parse_argv_flags( int argc, char const * const * argv,
5055 cson_object ** tgt, unsigned int * count ){
5056 cson_object * o = NULL;
5057 int rc = 0;
5058 int i = 0;
5059 if(argc<1 || !argc || !tgt) return CSON_RC_ArgError;
5060 o = *tgt ? *tgt : cson_new_object();
5061 if(count) *count = 0;
5062 for( i = 0; i < argc; ++i ){
5063 char const * arg = argv[i];
5064 char const * key = arg;
@@ -5068,11 +5070,11 @@
5070 if(!*key) continue;
5071 pos = key;
5072 while( *pos && ('=' != *pos)) ++pos;
5073 k = cson_new_string(key, pos-key);
5074 if(!k){
5075 rc = CSON_RC_AllocError;
5076 break;
5077 }
5078 if(!*pos){ /** --key */
5079 v = cson_value_true();
5080 }else{ /** --key=...*/
@@ -5389,11 +5391,11 @@
5391 cson_string * colName = NULL;
5392 int i = 0;
5393 int rc = 0;
5394 cson_value * currentValue = NULL;
5395 int const colCount = sqlite3_column_count(st);
5396 if( !colCount || (colCount>cson_array_length_get(colNames)) ) {
5397 return NULL;
5398 }
5399 rootV = cson_value_new_object();
5400 if(!rootV) return NULL;
5401 root = cson_value_get_object(rootV);
5402
--- extsrc/cson_amalgamation.h
+++ extsrc/cson_amalgamation.h
@@ -7,10 +7,12 @@
77
#if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
88
#define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
99
1010
/*#include <stdint.h> C99: fixed-size int types. */
1111
#include <stdio.h> /* FILE decl */
12
+
13
+#include <stdarg.h>
1214
1315
/** @page page_cson cson JSON API
1416
1517
cson (pronounced "season") is an object-oriented C API for generating
1618
and consuming JSON (http://www.json.org) data.
@@ -19,24 +21,22 @@
1921
to, damned near anywhere. The i/o routines use a callback function to
2022
fetch/emit JSON data, allowing clients to easily plug in their own
2123
implementations. Implementations are provided for string- and
2224
FILE-based i/o.
2325
24
-Project home page: http://fossil.wanderinghorse.net/repos/cson
26
+Project home page: https://fossil.wanderinghorse.net/r/cson
2527
26
-Author: Stephan Beal (http://www.wanderinghorse.net/home/stephan/)
28
+Author: Stephan Beal (https://www.wanderinghorse.net/home/stephan/)
2729
2830
License: Dual Public Domain/MIT
2931
3032
The full license text is at the bottom of the main header file
3133
(cson.h).
3234
3335
Examples of how to use the library are scattered throughout
3436
the API documentation, in the test.c file in the source repo,
3537
and in the wiki on the project's home page.
36
-
37
-
3838
*/
3939
4040
#if defined(__cplusplus)
4141
extern "C" {
4242
#endif
@@ -296,10 +296,14 @@
296296
@see cson_value_type_id()
297297
*/
298298
299299
/** @var cson_rc
300300
301
+ Deprecated: clients are encouraged to use the CSON_RC_xxx values
302
+ which correspond to cson_rc.xxx, as those are more efficient. Some
303
+ docs and code may still refer to cson_rc, though.
304
+
301305
This object defines the error codes used by cson.
302306
303307
Library routines which return int values almost always return a
304308
value from this structure. None of the members in this struct have
305309
published values except for the OK member, which has the value 0.
@@ -315,14 +319,106 @@
315319
if( 0 == rc ) {...success...}
316320
else if( cson_rc.ArgError == rc ) { ... some argument was wrong ... }
317321
else if( cson_rc.AllocError == rc ) { ... allocation error ... }
318322
...
319323
@endcode
324
+
325
+ Or with the preferred/newer method:
326
+
327
+ @code
328
+ int rc = cson_some_func(...);
329
+ switch(rc){
330
+ case 0: ...success...;
331
+ case CSON_RC_ArgError: ... some argument was wrong ...
332
+ case CSON_RC_AllocError: ... allocation error ...
333
+ ...
334
+ }
335
+ @endcode
320336
321337
The entries named Parse_XXX are generally only returned by
322338
cson_parse() and friends.
339
+
340
+ @deprecated
323341
*/
342
+
343
+/**
344
+ The CSON_RC_xxx values are intended to replace the older
345
+ cson_rc.xxx values.
346
+*/
347
+enum cson_rc_values {
348
+ /** The generic success value. Guaranteed to be 0. */
349
+ CSON_RC_OK = 0,
350
+ /** Signifies an error in one or more arguments (e.g. NULL where it is not allowed). */
351
+ CSON_RC_ArgError,
352
+ /** Signifies that some argument is not in a valid range. */
353
+ CSON_RC_RangeError,
354
+ /** Signifies that some argument is not of the correct logical cson type. */
355
+ CSON_RC_TypeError,
356
+ /** Signifies an input/ouput error. */
357
+ CSON_RC_IOError,
358
+ /** Signifies an out-of-memory error. */
359
+ CSON_RC_AllocError,
360
+ /** Signifies that the called code is "NYI" (Not Yet Implemented). */
361
+ CSON_RC_NYIError,
362
+ /** Signifies that an internal error was triggered. If it happens, please report this as a bug! */
363
+ CSON_RC_InternalError,
364
+ /** Signifies that the called operation is not supported in the
365
+ current environment. e.g. missing support from 3rd-party or
366
+ platform-specific code.
367
+ */
368
+ CSON_RC_UnsupportedError,
369
+ /**
370
+ Signifies that the request resource could not be found.
371
+ */
372
+ CSON_RC_NotFoundError,
373
+ /**
374
+ Signifies an unknown error, possibly because an underlying
375
+ 3rd-party API produced an error and we have no other reasonable
376
+ error code to convert it to.
377
+ */
378
+ CSON_RC_UnknownError,
379
+ /**
380
+ Signifies that the parser found an unexpected character.
381
+ */
382
+ CSON_RC_Parse_INVALID_CHAR,
383
+ /**
384
+ Signifies that the parser found an invalid keyword (possibly
385
+ an unquoted string).
386
+ */
387
+ CSON_RC_Parse_INVALID_KEYWORD,
388
+ /**
389
+ Signifies that the parser found an invalid escape sequence.
390
+ */
391
+ CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE,
392
+ /**
393
+ Signifies that the parser found an invalid Unicode character
394
+ sequence.
395
+ */
396
+ CSON_RC_Parse_INVALID_UNICODE_SEQUENCE,
397
+ /**
398
+ Signifies that the parser found an invalid numeric token.
399
+ */
400
+ CSON_RC_Parse_INVALID_NUMBER,
401
+ /**
402
+ Signifies that the parser reached its maximum defined
403
+ parsing depth before finishing the input.
404
+ */
405
+ CSON_RC_Parse_NESTING_DEPTH_REACHED,
406
+ /**
407
+ Signifies that the parser found an unclosed object or array.
408
+ */
409
+ CSON_RC_Parse_UNBALANCED_COLLECTION,
410
+ /**
411
+ Signifies that the parser found an key in an unexpected place.
412
+ */
413
+ CSON_RC_Parse_EXPECTED_KEY,
414
+ /**
415
+ Signifies that the parser expected to find a colon but
416
+ found none (e.g. between keys and values in an object).
417
+ */
418
+ CSON_RC_Parse_EXPECTED_COLON
419
+};
324420
325421
/** @struct cson_rc_
326422
See \ref cson_rc for details.
327423
*/
328424
static const struct cson_rc_
@@ -397,30 +493,30 @@
397493
Signifies that the parser expected to find a colon but
398494
found none (e.g. between keys and values in an object).
399495
*/
400496
const int Parse_EXPECTED_COLON;
401497
} cson_rc = {
402
-0/*OK*/,
403
-1/*ArgError*/,
404
-2/*RangeError*/,
405
-3/*TypeError*/,
406
-4/*IOError*/,
407
-5/*AllocError*/,
408
-6/*NYIError*/,
409
-7/*InternalError*/,
410
-8/*UnsupportedError*/,
411
-9/*NotFoundError*/,
412
-10/*UnknownError*/,
413
-11/*Parse_INVALID_CHAR*/,
414
-12/*Parse_INVALID_KEYWORD*/,
415
-13/*Parse_INVALID_ESCAPE_SEQUENCE*/,
416
-14/*Parse_INVALID_UNICODE_SEQUENCE*/,
417
-15/*Parse_INVALID_NUMBER*/,
418
-16/*Parse_NESTING_DEPTH_REACHED*/,
419
-17/*Parse_UNBALANCED_COLLECTION*/,
420
-18/*Parse_EXPECTED_KEY*/,
421
-19/*Parse_EXPECTED_COLON*/
498
+ CSON_RC_OK,
499
+ CSON_RC_ArgError,
500
+ CSON_RC_RangeError,
501
+ CSON_RC_TypeError,
502
+ CSON_RC_IOError,
503
+ CSON_RC_AllocError,
504
+ CSON_RC_NYIError,
505
+ CSON_RC_InternalError,
506
+ CSON_RC_UnsupportedError,
507
+ CSON_RC_NotFoundError,
508
+ CSON_RC_UnknownError,
509
+ CSON_RC_Parse_INVALID_CHAR,
510
+ CSON_RC_Parse_INVALID_KEYWORD,
511
+ CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE,
512
+ CSON_RC_Parse_INVALID_UNICODE_SEQUENCE,
513
+ CSON_RC_Parse_INVALID_NUMBER,
514
+ CSON_RC_Parse_NESTING_DEPTH_REACHED,
515
+ CSON_RC_Parse_UNBALANCED_COLLECTION,
516
+ CSON_RC_Parse_EXPECTED_KEY,
517
+ CSON_RC_Parse_EXPECTED_COLON
422518
};
423519
424520
/**
425521
Returns the string form of the cson_rc code corresponding to rc, or
426522
some unspecified, non-NULL string if it is an unknown code.
@@ -671,12 +767,12 @@
671767
so any output-destination-specific state can be stored there and accessed
672768
via the src callback.
673769
674770
Non-parse error conditions include:
675771
676
- - (!tgt) or !src: cson_rc.ArgError
677
- - cson_rc.AllocError can happen at any time during the input phase
772
+ - (!tgt) or !src: CSON_RC_ArgError
773
+ - CSON_RC_AllocError can happen at any time during the input phase
678774
679775
Here's a complete example of using a custom input source:
680776
681777
@code
682778
// Internal type to hold state for a JSON input string.
@@ -692,12 +788,12 @@
692788
unsigned int * n )
693789
{
694790
StringSource * ss = (StringSource*) state;
695791
unsigned int i;
696792
unsigned char * tgt = (unsigned char *)dest;
697
- if( ! ss || ! n || !dest ) return cson_rc.ArgError;
698
- else if( !*n ) return cson_rc.RangeError;
793
+ if( ! ss || ! n || !dest ) return CSON_RC_ArgError;
794
+ else if( !*n ) return CSON_RC_RangeError;
699795
for( i = 0;
700796
(i < *n) && (ss->pos < ss->end);
701797
++i, ++ss->pos, ++tgt )
702798
{
703799
*tgt = *ss->pos;
@@ -748,11 +844,11 @@
748844
cson_parse_opt const * opt, cson_parse_info * info );
749845
750846
/**
751847
Convenience wrapper around cson_parse_FILE() which opens the given filename.
752848
753
- Returns cson_rc.IOError if the file cannot be opened.
849
+ Returns CSON_RC_IOError if the file cannot be opened.
754850
755851
@see cson_parse_FILE()
756852
*/
757853
int cson_parse_filename( cson_value ** tgt, char const * src,
758854
cson_parse_opt const * opt, cson_parse_info * info );
@@ -763,11 +859,11 @@
763859
764860
src must be a string containing JSON code, at least len bytes long,
765861
and the parser will attempt to parse exactly len bytes from src.
766862
767863
If len is less than 2 (the minimum length of a legal top-node JSON
768
- object) then cson_rc.RangeError is returned.
864
+ object) then CSON_RC_RangeError is returned.
769865
*/
770866
int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
771867
cson_parse_opt const * opt, cson_parse_info * info );
772868
773869
@@ -779,11 +875,11 @@
779875
780876
If opt is NULL then default options (the values defined in
781877
cson_output_opt_empty) are used.
782878
783879
If opt->maxDepth is exceeded while traversing the value tree,
784
- cson_rc.RangeError is returned.
880
+ CSON_RC_RangeError is returned.
785881
786882
The destState parameter is ignored by this function and is passed
787883
on to the dest function.
788884
789885
Returns 0 on success. On error, any amount of output might have been
@@ -816,11 +912,11 @@
816912
@see cson_output_filename()
817913
*/
818914
int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * opt );
819915
/**
820916
Convenience wrapper around cson_output_FILE() which writes to the given filename, destroying
821
- any existing contents. Returns cson_rc.IOError if the file cannot be opened.
917
+ any existing contents. Returns CSON_RC_IOError if the file cannot be opened.
822918
823919
@see cson_output_FILE()
824920
*/
825921
int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt );
826922
@@ -947,11 +1043,11 @@
9471043
The conversion, if any, depends on the concrete type of val:
9481044
9491045
NULL, null, undefined: *v is set to 0 and 0 is returned.
9501046
9511047
string, object, array: *v is set to 0 and
952
- cson_rc.TypeError is returned. The error may normally be safely
1048
+ CSON_RC_TypeError is returned. The error may normally be safely
9531049
ignored, but it is provided for those wanted to know whether a direct
9541050
conversion was possible.
9551051
9561052
integer: *v is set to the int value and 0 is returned.
9571053
@@ -1178,19 +1274,19 @@
11781274
changes its logical size, but may pre-allocate space in the
11791275
array for storing new (as-yet-unassigned) values.
11801276
11811277
Returns 0 on success, or non-zero on error:
11821278
1183
- - If ar is NULL: cson_rc.ArgError
1279
+ - If ar is NULL: CSON_RC_ArgError
11841280
1185
- - If allocation fails: cson_rc.AllocError
1281
+ - If allocation fails: CSON_RC_AllocError
11861282
*/
11871283
int cson_array_reserve( cson_array * ar, unsigned int size );
11881284
11891285
/**
11901286
If ar is not NULL, sets *v (if v is not NULL) to the length of the array
1191
- and returns 0. Returns cson_rc.ArgError if ar is NULL.
1287
+ and returns 0. Returns CSON_RC_ArgError if ar is NULL.
11921288
*/
11931289
int cson_array_length_fetch( cson_array const * ar, unsigned int * v );
11941290
11951291
/**
11961292
Simplified form of cson_array_length_fetch() which returns 0 if ar
@@ -1243,16 +1339,16 @@
12431339
implementation has slightly different array-preallocation policy
12441340
(it grows more eagerly).
12451341
12461342
Returns 0 on success, non-zero on error. Error cases include:
12471343
1248
- - ar or v are NULL: cson_rc.ArgError
1344
+ - ar or v are NULL: CSON_RC_ArgError
12491345
1250
- - Array cannot be expanded to hold enough elements: cson_rc.AllocError.
1346
+ - Array cannot be expanded to hold enough elements: CSON_RC_AllocError.
12511347
12521348
- Appending would cause a numeric overlow in the array's size:
1253
- cson_rc.RangeError. (However, you'll get an AllocError long before
1349
+ CSON_RC_RangeError. (However, you'll get an AllocError long before
12541350
that happens!)
12551351
12561352
On error ownership of v is NOT modified, and the caller may still
12571353
need to clean it up. See cson_array_set() for the details.
12581354
@@ -1449,13 +1545,13 @@
14491545
show up later, e.g. during output.
14501546
14511547
Returns 0 on success, non-0 on error. It has the following error
14521548
cases:
14531549
1454
- - cson_rc.ArgError: obj or key are NULL or strlen(key) is 0.
1550
+ - CSON_RC_ArgError: obj or key are NULL or strlen(key) is 0.
14551551
1456
- - cson_rc.AllocError: an out-of-memory error
1552
+ - CSON_RC_AllocError: an out-of-memory error
14571553
14581554
On error ownership of v is NOT modified, and the caller may still
14591555
need to clean it up. For example, the following code will introduce
14601556
a leak if this function fails:
14611557
@@ -1500,14 +1596,14 @@
15001596
15011597
/**
15021598
Removes a property from an object.
15031599
15041600
If obj contains the given key, it is removed and 0 is returned. If
1505
- it is not found, cson_rc.NotFoundError is returned (which can
1601
+ it is not found, CSON_RC_NotFoundError is returned (which can
15061602
normally be ignored by client code).
15071603
1508
- cson_rc.ArgError is returned if obj or key are NULL or key has
1604
+ CSON_RC_ArgError is returned if obj or key are NULL or key has
15091605
a length of 0.
15101606
15111607
Returns 0 if the given key is found and removed.
15121608
15131609
This is functionally equivalent calling
@@ -1563,27 +1659,27 @@
15631659
path is a delimited string, where the delimiter is the given
15641660
separator character.
15651661
15661662
This function searches for the given path, starting at the given object
15671663
and traversing its properties as the path specifies. If a given part of the
1568
- path is not found, then this function fails with cson_rc.NotFoundError.
1664
+ path is not found, then this function fails with CSON_RC_NotFoundError.
15691665
15701666
If it finds the given path, it returns the value by assiging *tgt
15711667
to it. If tgt is NULL then this function has no side-effects but
15721668
will return 0 if the given path is found within the object, so it can be used
15731669
to test for existence without fetching it.
15741670
1575
- Returns 0 if it finds an entry, cson_rc.NotFoundError if it finds
1671
+ Returns 0 if it finds an entry, CSON_RC_NotFoundError if it finds
15761672
no item, and any other non-zero error code on a "real" error. Errors include:
15771673
1578
- - obj or path are NULL: cson_rc.ArgError
1674
+ - obj or path are NULL: CSON_RC_ArgError
15791675
15801676
- separator is 0, or path is an empty string or contains only
1581
- separator characters: cson_rc.RangeError
1677
+ separator characters: CSON_RC_RangeError
15821678
15831679
- There is an upper limit on how long a single path component may
1584
- be (some "reasonable" internal size), and cson_rc.RangeError is
1680
+ be (some "reasonable" internal size), and CSON_RC_RangeError is
15851681
returned if that length is violated.
15861682
15871683
15881684
Limitations:
15891685
@@ -1677,11 +1773,11 @@
16771773
either replaced or left as-is, depending on whether flags contains
16781774
he CSON_MERGE_REPLACE bit.
16791775
16801776
Returns 0 on success. The error conditions are:
16811777
1682
- - dest or src are NULL or (dest==src) returns cson_rc.ArgError.
1778
+ - dest or src are NULL or (dest==src) returns CSON_RC_ArgError.
16831779
16841780
- dest or src contain cyclic references - this will likely cause a
16851781
crash due to endless recursion.
16861782
16871783
Potential TODOs:
@@ -1724,11 +1820,11 @@
17241820
*/
17251821
extern const cson_object_iterator cson_object_iterator_empty;
17261822
17271823
/**
17281824
Initializes the given iterator to point at the start of obj's
1729
- properties. Returns 0 on success or cson_rc.ArgError if !obj
1825
+ properties. Returns 0 on success or CSON_RC_ArgError if !obj
17301826
or !iter.
17311827
17321828
obj must outlive iter, or results are undefined. Results are also
17331829
undefined if obj is modified while the iterator is active.
17341830
@@ -1891,13 +1987,13 @@
18911987
to be NULL-terminated. On error the buffer might contain partial
18921988
contents, and it should not be used except to free its contents.
18931989
18941990
On error non-zero is returned. Errors include:
18951991
1896
- - Invalid arguments: cson_rc.ArgError
1992
+ - Invalid arguments: CSON_RC_ArgError
18971993
1898
- - Buffer cannot be expanded (runs out of memory): cson_rc.AllocError
1994
+ - Buffer cannot be expanded (runs out of memory): CSON_RC_AllocError
18991995
19001996
Example usage:
19011997
19021998
@code
19031999
cson_buffer buf = cson_buffer_empty;
@@ -1999,13 +2095,13 @@
19992095
On error non-0 is returned and dest has almost certainly been
20002096
modified but its state must be considered incomplete.
20012097
20022098
Errors include:
20032099
2004
- - dest or src are NULL (cson_rc.ArgError)
2100
+ - dest or src are NULL (CSON_RC_ArgError)
20052101
2006
- - Allocation error (cson_rc.AllocError)
2102
+ - Allocation error (CSON_RC_AllocError)
20072103
20082104
- src() returns an error code
20092105
20102106
Whether or not the state parameter may be NULL depends on
20112107
the src implementation requirements.
@@ -2084,12 +2180,12 @@
20842180
will not be if there are still other live references to
20852181
it). cson_value_free() will not _actually_ destroy the value until
20862182
its reference count drops to 0.
20872183
20882184
Returns 0 on success. The only error conditions are if v is NULL
2089
- (cson_rc.ArgError) or if the reference increment would overflow
2090
- (cson_rc.RangeError). In theory a client would get allocation
2185
+ (CSON_RC_ArgError) or if the reference increment would overflow
2186
+ (CSON_RC_RangeError). In theory a client would get allocation
20912187
errors long before the reference count could overflow (assuming
20922188
those reference counts come from container insertions, as opposed
20932189
to via this function).
20942190
20952191
Insider notes which clients really need to know:
@@ -2238,11 +2334,11 @@
22382334
/**
22392335
Calculates the approximate in-memory-allocated size of v,
22402336
recursively if it is a container type, with the following caveats
22412337
and limitations:
22422338
2243
- If a given value is reference counted then it is only and multiple
2339
+ If a given value is reference counted and encountered multiple
22442340
times within a traversed container, each reference is counted at
22452341
full cost. We have no way of knowing if a given reference has been
22462342
visited already and whether it should or should not be counted, so
22472343
we pessimistically count them even though the _might_ not really
22482344
count for the given object tree (it depends on where the other open
@@ -2318,10 +2414,169 @@
23182414
it might contain partial results.
23192415
*/
23202416
int cson_parse_argv_flags( int argc, char const * const * argv,
23212417
cson_object ** tgt, unsigned int * count );
23222418
2419
+/**
2420
+ Return values for the cson_pack() and cson_unpack() interfaces.
2421
+*/
2422
+enum cson_pack_retval {
2423
+ /** Signals an out-of-memory error. */
2424
+ CSON_PACK_ALLOC_ERROR = -1,
2425
+ /** Signals a syntax error in the format string. */
2426
+ CSON_PACK_ARG_ERROR = -2,
2427
+ /**
2428
+ Signals an that an internal error has occurred.
2429
+ This indicates a bug in this library.
2430
+ */
2431
+ CSON_PACK_INTERNAL_ERROR = -3,
2432
+ /**
2433
+ Signals that the JSON document does not validate agains the format
2434
+ string passed to cson_unpack().
2435
+ */
2436
+ CSON_PACK_VALIDATION_ERROR = -4
2437
+};
2438
+
2439
+/**
2440
+ Construct arbitrarily complex JSON documents from native C types.
2441
+
2442
+ Create a new object or array and add or merge the passed values and
2443
+ properties to it according to the supplied format string.
2444
+
2445
+ fmt is a format string, it must at least contain an array or object
2446
+ specifier as its root value. Format specifiers start with a percent sign '\%'
2447
+ followed by one or more modifiers and a type character. Object properties
2448
+ are specified as key-value pairs where the key is specified as a string and
2449
+ passed as an argument of const char *. Any space, tab, carriage return, line
2450
+ feed, colon and comma characters between format specifiers are ignored.
2451
+
2452
+ | Type | Description |
2453
+ | :--: | :---------- |
2454
+ | s | creates either a property name or a string value, in case of the former the corresponding argument is a pointer to const char which is a sequence of bytes specifying the name of the property that is to be created, in case of the latter the corresponding argument is a pointer to const char |
2455
+ | d | creates an integer value, the corresponding argument is an int |
2456
+ | i | ^ |
2457
+ | f | creates a floating point value, the corresponding argument is a double |
2458
+ | b | creates a boolean value, the corresponding argument is an int |
2459
+ | N | creates a null value |
2460
+ | [...] | creates an array, the corresponding argument is a pointer to a cson_array |
2461
+ | {...} | creates an array, the corresponding argument is a pointer to a cson_object |
2462
+
2463
+ | Modifier | Description |
2464
+ | :------: | :---------- |
2465
+ | l | specifies that the following d or i specifier applies to an argument which is a pointer to long |
2466
+ | ll | specifies that the following d or i specifier applies to an argument which is a pointer to cson_int_t |
2467
+
2468
+ | Short Form | Expands to
2469
+ | :--------: | :--------- |
2470
+ | {...} | %*{...} |
2471
+ | [...] | %*[...] |
2472
+ | \%D | \%lld |
2473
+
2474
+
2475
+ Returns 0 on success. The error conditions are:
2476
+
2477
+ - CSON_PACK_ARG_ERROR: fmt contains a syntax error
2478
+
2479
+ - CSON_PACK_ALLOC_ERROR: a memory allocation failed
2480
+
2481
+ - CSON_PACK_INTERNAL_ERROR: an internal error has occurred, this is a bug in
2482
+ cson
2483
+
2484
+ Example:
2485
+ @code
2486
+ cson_value * root_value;
2487
+ cson_array * arr;
2488
+ ...
2489
+ rc = cson_pack( root_value, "{%s: %d, %s: %[]}", "foo", 42, "bar", arr );
2490
+ if( 0 != rc ) {
2491
+ ... error ...
2492
+ }
2493
+ @endcode
2494
+*/
2495
+int cson_pack( cson_value **root_valuep, const char *fmt, ... );
2496
+
2497
+/**
2498
+ Same as cson_pack() except that it takes a va_list instead of a variable
2499
+ number of arguments.
2500
+*/
2501
+int cson_vpack( cson_value **root_valuep, const char *fmt, va_list args );
2502
+
2503
+/**
2504
+ Iterate over the given object or array and convert an arbitrary number of
2505
+ JSON values into their native C types or validates them according to the
2506
+ given format string fmt.
2507
+
2508
+ fmt is a format string, it must at least contain an array or object
2509
+ specifier as its root value. Format specifiers start with a percent sign '\%'
2510
+ followed by one or more modifiers and a type character. Object properties
2511
+ are specified as key-value pairs where the key is specified as a string and
2512
+ passed as an argument of const char *. Any space, tab, carriage return, line
2513
+ feed, colon and comma characters between format specifiers are ignored.
2514
+
2515
+ | Type | Description |
2516
+ | :--: | :---------- |
2517
+ | s | matches a either a property name or a string value, in case of the former the corresponding argument is a pointer to const char which is a sequence of bytes specifying the name of the property that is to be matched, in case of the latter the corresponding argument is a pointer to a pointer to const char unless the 'm' modifier is specified where the the corresponding argument is a pointer to a pointer to char |
2518
+ | d | matches an integer value and must be used in with the "ll" modifier, the corresponding argument is a pointer to cson_int_t |
2519
+ | i | ^ |
2520
+ | f | matches a floating point value, the corresponding argument is a pointer to double |
2521
+ | b | matches a boolean value, the corresponding argument is a pointer to int |
2522
+ | N | matches a null value |
2523
+ | [...] | matches an array, the corresponding argument is a pointer to a pointer to a cson_array |
2524
+ | {...} | matches an array, the corresponding argument is a pointer to a pointer to a cson_object |
2525
+
2526
+ | Modifier | Description |
2527
+ | :------: | :---------- |
2528
+ | ? | specifies that the property reffered to by the given property name is optional |
2529
+ | * | suppresses assignment, only check for the presence and type of the specified value |
2530
+ | m | allocates a memory buffer for the extracted string |
2531
+ | ll | specifies that the following d or i specifier applies to an argument which is a pointer to cson_int_t |
2532
+
2533
+ | Short Form | Expands to
2534
+ | :--------: | :--------- |
2535
+ | {...} | %*{...} |
2536
+ | [...] | %*[...] |
2537
+ | \%D | \%lld |
2538
+
2539
+ Returns 0 on success. The error conditions are:
2540
+
2541
+ - CSON_PACK_ARG_ERROR: fmt contains a syntax error
2542
+
2543
+ - CSON_PACK_ALLOC_ERROR: a memory allocation failed
2544
+
2545
+ - CSON_PACK_VALIDATION_ERROR: validation failed, the JSON document structure
2546
+ differs from that described by the format string
2547
+
2548
+ - CSON_PACK_INTERNAL_ERROR: an internal error has occurred, this
2549
+ indicates a bug in this library.
2550
+
2551
+ Example:
2552
+ @code
2553
+ cson_value * root_value;
2554
+ cson_int_t x = 0;
2555
+ cson_array * arr = NULL;
2556
+ const char *str = NULL;
2557
+ ...
2558
+ rc = cson_unpack( root_value, "{%s: %d, %s: %[], %?s: %s}", "foo", &x, "bar", &arr, "baz", &str );
2559
+ if( rc < 3 && rc >= 0 ) {
2560
+ ... optional property is missing ...
2561
+ } else if ( CSON_PACK_ALLOC_ERROR == rc ) {
2562
+ ... out of memory error ...
2563
+ } else if ( CSON_PACK_VALIDATION_ERROR == rc ) {
2564
+ ... unexpected JSON document structure ...
2565
+ } else if ( rc ) {
2566
+ ... internal error ...
2567
+ }
2568
+ @endcode
2569
+
2570
+*/
2571
+int cson_unpack( cson_value *root_value, const char *fmt, ... );
2572
+
2573
+/**
2574
+ Same as cson_unpack() except that it takes a va_list instead of a variable
2575
+ number of arguments.
2576
+*/
2577
+int cson_vunpack( cson_value *root_value, const char *fmt, va_list args );
23232578
23242579
/* LICENSE
23252580
23262581
This software's source code, including accompanying documentation and
23272582
demonstration applications, are licensed under the following
@@ -2416,11 +2671,11 @@
24162671
#define CSON_ENABLE_SQLITE3 1
24172672
# endif
24182673
#endif
24192674
24202675
#if CSON_ENABLE_SQLITE3 /* we do this here for the sake of the amalgamation build */
2421
-#include <sqlite3.h>
2676
+#include "sqlite3.h"
24222677
24232678
#if defined(__cplusplus)
24242679
extern "C" {
24252680
#endif
24262681
24272682
--- extsrc/cson_amalgamation.h
+++ extsrc/cson_amalgamation.h
@@ -7,10 +7,12 @@
7 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
8 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
9
10 /*#include <stdint.h> C99: fixed-size int types. */
11 #include <stdio.h> /* FILE decl */
 
 
12
13 /** @page page_cson cson JSON API
14
15 cson (pronounced "season") is an object-oriented C API for generating
16 and consuming JSON (http://www.json.org) data.
@@ -19,24 +21,22 @@
19 to, damned near anywhere. The i/o routines use a callback function to
20 fetch/emit JSON data, allowing clients to easily plug in their own
21 implementations. Implementations are provided for string- and
22 FILE-based i/o.
23
24 Project home page: http://fossil.wanderinghorse.net/repos/cson
25
26 Author: Stephan Beal (http://www.wanderinghorse.net/home/stephan/)
27
28 License: Dual Public Domain/MIT
29
30 The full license text is at the bottom of the main header file
31 (cson.h).
32
33 Examples of how to use the library are scattered throughout
34 the API documentation, in the test.c file in the source repo,
35 and in the wiki on the project's home page.
36
37
38 */
39
40 #if defined(__cplusplus)
41 extern "C" {
42 #endif
@@ -296,10 +296,14 @@
296 @see cson_value_type_id()
297 */
298
299 /** @var cson_rc
300
 
 
 
 
301 This object defines the error codes used by cson.
302
303 Library routines which return int values almost always return a
304 value from this structure. None of the members in this struct have
305 published values except for the OK member, which has the value 0.
@@ -315,14 +319,106 @@
315 if( 0 == rc ) {...success...}
316 else if( cson_rc.ArgError == rc ) { ... some argument was wrong ... }
317 else if( cson_rc.AllocError == rc ) { ... allocation error ... }
318 ...
319 @endcode
 
 
 
 
 
 
 
 
 
 
 
 
320
321 The entries named Parse_XXX are generally only returned by
322 cson_parse() and friends.
 
 
323 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
325 /** @struct cson_rc_
326 See \ref cson_rc for details.
327 */
328 static const struct cson_rc_
@@ -397,30 +493,30 @@
397 Signifies that the parser expected to find a colon but
398 found none (e.g. between keys and values in an object).
399 */
400 const int Parse_EXPECTED_COLON;
401 } cson_rc = {
402 0/*OK*/,
403 1/*ArgError*/,
404 2/*RangeError*/,
405 3/*TypeError*/,
406 4/*IOError*/,
407 5/*AllocError*/,
408 6/*NYIError*/,
409 7/*InternalError*/,
410 8/*UnsupportedError*/,
411 9/*NotFoundError*/,
412 10/*UnknownError*/,
413 11/*Parse_INVALID_CHAR*/,
414 12/*Parse_INVALID_KEYWORD*/,
415 13/*Parse_INVALID_ESCAPE_SEQUENCE*/,
416 14/*Parse_INVALID_UNICODE_SEQUENCE*/,
417 15/*Parse_INVALID_NUMBER*/,
418 16/*Parse_NESTING_DEPTH_REACHED*/,
419 17/*Parse_UNBALANCED_COLLECTION*/,
420 18/*Parse_EXPECTED_KEY*/,
421 19/*Parse_EXPECTED_COLON*/
422 };
423
424 /**
425 Returns the string form of the cson_rc code corresponding to rc, or
426 some unspecified, non-NULL string if it is an unknown code.
@@ -671,12 +767,12 @@
671 so any output-destination-specific state can be stored there and accessed
672 via the src callback.
673
674 Non-parse error conditions include:
675
676 - (!tgt) or !src: cson_rc.ArgError
677 - cson_rc.AllocError can happen at any time during the input phase
678
679 Here's a complete example of using a custom input source:
680
681 @code
682 // Internal type to hold state for a JSON input string.
@@ -692,12 +788,12 @@
692 unsigned int * n )
693 {
694 StringSource * ss = (StringSource*) state;
695 unsigned int i;
696 unsigned char * tgt = (unsigned char *)dest;
697 if( ! ss || ! n || !dest ) return cson_rc.ArgError;
698 else if( !*n ) return cson_rc.RangeError;
699 for( i = 0;
700 (i < *n) && (ss->pos < ss->end);
701 ++i, ++ss->pos, ++tgt )
702 {
703 *tgt = *ss->pos;
@@ -748,11 +844,11 @@
748 cson_parse_opt const * opt, cson_parse_info * info );
749
750 /**
751 Convenience wrapper around cson_parse_FILE() which opens the given filename.
752
753 Returns cson_rc.IOError if the file cannot be opened.
754
755 @see cson_parse_FILE()
756 */
757 int cson_parse_filename( cson_value ** tgt, char const * src,
758 cson_parse_opt const * opt, cson_parse_info * info );
@@ -763,11 +859,11 @@
763
764 src must be a string containing JSON code, at least len bytes long,
765 and the parser will attempt to parse exactly len bytes from src.
766
767 If len is less than 2 (the minimum length of a legal top-node JSON
768 object) then cson_rc.RangeError is returned.
769 */
770 int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
771 cson_parse_opt const * opt, cson_parse_info * info );
772
773
@@ -779,11 +875,11 @@
779
780 If opt is NULL then default options (the values defined in
781 cson_output_opt_empty) are used.
782
783 If opt->maxDepth is exceeded while traversing the value tree,
784 cson_rc.RangeError is returned.
785
786 The destState parameter is ignored by this function and is passed
787 on to the dest function.
788
789 Returns 0 on success. On error, any amount of output might have been
@@ -816,11 +912,11 @@
816 @see cson_output_filename()
817 */
818 int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * opt );
819 /**
820 Convenience wrapper around cson_output_FILE() which writes to the given filename, destroying
821 any existing contents. Returns cson_rc.IOError if the file cannot be opened.
822
823 @see cson_output_FILE()
824 */
825 int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt );
826
@@ -947,11 +1043,11 @@
947 The conversion, if any, depends on the concrete type of val:
948
949 NULL, null, undefined: *v is set to 0 and 0 is returned.
950
951 string, object, array: *v is set to 0 and
952 cson_rc.TypeError is returned. The error may normally be safely
953 ignored, but it is provided for those wanted to know whether a direct
954 conversion was possible.
955
956 integer: *v is set to the int value and 0 is returned.
957
@@ -1178,19 +1274,19 @@
1178 changes its logical size, but may pre-allocate space in the
1179 array for storing new (as-yet-unassigned) values.
1180
1181 Returns 0 on success, or non-zero on error:
1182
1183 - If ar is NULL: cson_rc.ArgError
1184
1185 - If allocation fails: cson_rc.AllocError
1186 */
1187 int cson_array_reserve( cson_array * ar, unsigned int size );
1188
1189 /**
1190 If ar is not NULL, sets *v (if v is not NULL) to the length of the array
1191 and returns 0. Returns cson_rc.ArgError if ar is NULL.
1192 */
1193 int cson_array_length_fetch( cson_array const * ar, unsigned int * v );
1194
1195 /**
1196 Simplified form of cson_array_length_fetch() which returns 0 if ar
@@ -1243,16 +1339,16 @@
1243 implementation has slightly different array-preallocation policy
1244 (it grows more eagerly).
1245
1246 Returns 0 on success, non-zero on error. Error cases include:
1247
1248 - ar or v are NULL: cson_rc.ArgError
1249
1250 - Array cannot be expanded to hold enough elements: cson_rc.AllocError.
1251
1252 - Appending would cause a numeric overlow in the array's size:
1253 cson_rc.RangeError. (However, you'll get an AllocError long before
1254 that happens!)
1255
1256 On error ownership of v is NOT modified, and the caller may still
1257 need to clean it up. See cson_array_set() for the details.
1258
@@ -1449,13 +1545,13 @@
1449 show up later, e.g. during output.
1450
1451 Returns 0 on success, non-0 on error. It has the following error
1452 cases:
1453
1454 - cson_rc.ArgError: obj or key are NULL or strlen(key) is 0.
1455
1456 - cson_rc.AllocError: an out-of-memory error
1457
1458 On error ownership of v is NOT modified, and the caller may still
1459 need to clean it up. For example, the following code will introduce
1460 a leak if this function fails:
1461
@@ -1500,14 +1596,14 @@
1500
1501 /**
1502 Removes a property from an object.
1503
1504 If obj contains the given key, it is removed and 0 is returned. If
1505 it is not found, cson_rc.NotFoundError is returned (which can
1506 normally be ignored by client code).
1507
1508 cson_rc.ArgError is returned if obj or key are NULL or key has
1509 a length of 0.
1510
1511 Returns 0 if the given key is found and removed.
1512
1513 This is functionally equivalent calling
@@ -1563,27 +1659,27 @@
1563 path is a delimited string, where the delimiter is the given
1564 separator character.
1565
1566 This function searches for the given path, starting at the given object
1567 and traversing its properties as the path specifies. If a given part of the
1568 path is not found, then this function fails with cson_rc.NotFoundError.
1569
1570 If it finds the given path, it returns the value by assiging *tgt
1571 to it. If tgt is NULL then this function has no side-effects but
1572 will return 0 if the given path is found within the object, so it can be used
1573 to test for existence without fetching it.
1574
1575 Returns 0 if it finds an entry, cson_rc.NotFoundError if it finds
1576 no item, and any other non-zero error code on a "real" error. Errors include:
1577
1578 - obj or path are NULL: cson_rc.ArgError
1579
1580 - separator is 0, or path is an empty string or contains only
1581 separator characters: cson_rc.RangeError
1582
1583 - There is an upper limit on how long a single path component may
1584 be (some "reasonable" internal size), and cson_rc.RangeError is
1585 returned if that length is violated.
1586
1587
1588 Limitations:
1589
@@ -1677,11 +1773,11 @@
1677 either replaced or left as-is, depending on whether flags contains
1678 he CSON_MERGE_REPLACE bit.
1679
1680 Returns 0 on success. The error conditions are:
1681
1682 - dest or src are NULL or (dest==src) returns cson_rc.ArgError.
1683
1684 - dest or src contain cyclic references - this will likely cause a
1685 crash due to endless recursion.
1686
1687 Potential TODOs:
@@ -1724,11 +1820,11 @@
1724 */
1725 extern const cson_object_iterator cson_object_iterator_empty;
1726
1727 /**
1728 Initializes the given iterator to point at the start of obj's
1729 properties. Returns 0 on success or cson_rc.ArgError if !obj
1730 or !iter.
1731
1732 obj must outlive iter, or results are undefined. Results are also
1733 undefined if obj is modified while the iterator is active.
1734
@@ -1891,13 +1987,13 @@
1891 to be NULL-terminated. On error the buffer might contain partial
1892 contents, and it should not be used except to free its contents.
1893
1894 On error non-zero is returned. Errors include:
1895
1896 - Invalid arguments: cson_rc.ArgError
1897
1898 - Buffer cannot be expanded (runs out of memory): cson_rc.AllocError
1899
1900 Example usage:
1901
1902 @code
1903 cson_buffer buf = cson_buffer_empty;
@@ -1999,13 +2095,13 @@
1999 On error non-0 is returned and dest has almost certainly been
2000 modified but its state must be considered incomplete.
2001
2002 Errors include:
2003
2004 - dest or src are NULL (cson_rc.ArgError)
2005
2006 - Allocation error (cson_rc.AllocError)
2007
2008 - src() returns an error code
2009
2010 Whether or not the state parameter may be NULL depends on
2011 the src implementation requirements.
@@ -2084,12 +2180,12 @@
2084 will not be if there are still other live references to
2085 it). cson_value_free() will not _actually_ destroy the value until
2086 its reference count drops to 0.
2087
2088 Returns 0 on success. The only error conditions are if v is NULL
2089 (cson_rc.ArgError) or if the reference increment would overflow
2090 (cson_rc.RangeError). In theory a client would get allocation
2091 errors long before the reference count could overflow (assuming
2092 those reference counts come from container insertions, as opposed
2093 to via this function).
2094
2095 Insider notes which clients really need to know:
@@ -2238,11 +2334,11 @@
2238 /**
2239 Calculates the approximate in-memory-allocated size of v,
2240 recursively if it is a container type, with the following caveats
2241 and limitations:
2242
2243 If a given value is reference counted then it is only and multiple
2244 times within a traversed container, each reference is counted at
2245 full cost. We have no way of knowing if a given reference has been
2246 visited already and whether it should or should not be counted, so
2247 we pessimistically count them even though the _might_ not really
2248 count for the given object tree (it depends on where the other open
@@ -2318,10 +2414,169 @@
2318 it might contain partial results.
2319 */
2320 int cson_parse_argv_flags( int argc, char const * const * argv,
2321 cson_object ** tgt, unsigned int * count );
2322
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2323
2324 /* LICENSE
2325
2326 This software's source code, including accompanying documentation and
2327 demonstration applications, are licensed under the following
@@ -2416,11 +2671,11 @@
2416 #define CSON_ENABLE_SQLITE3 1
2417 # endif
2418 #endif
2419
2420 #if CSON_ENABLE_SQLITE3 /* we do this here for the sake of the amalgamation build */
2421 #include <sqlite3.h>
2422
2423 #if defined(__cplusplus)
2424 extern "C" {
2425 #endif
2426
2427
--- extsrc/cson_amalgamation.h
+++ extsrc/cson_amalgamation.h
@@ -7,10 +7,12 @@
7 #if !defined(WANDERINGHORSE_NET_CSON_H_INCLUDED)
8 #define WANDERINGHORSE_NET_CSON_H_INCLUDED 1
9
10 /*#include <stdint.h> C99: fixed-size int types. */
11 #include <stdio.h> /* FILE decl */
12
13 #include <stdarg.h>
14
15 /** @page page_cson cson JSON API
16
17 cson (pronounced "season") is an object-oriented C API for generating
18 and consuming JSON (http://www.json.org) data.
@@ -19,24 +21,22 @@
21 to, damned near anywhere. The i/o routines use a callback function to
22 fetch/emit JSON data, allowing clients to easily plug in their own
23 implementations. Implementations are provided for string- and
24 FILE-based i/o.
25
26 Project home page: https://fossil.wanderinghorse.net/r/cson
27
28 Author: Stephan Beal (https://www.wanderinghorse.net/home/stephan/)
29
30 License: Dual Public Domain/MIT
31
32 The full license text is at the bottom of the main header file
33 (cson.h).
34
35 Examples of how to use the library are scattered throughout
36 the API documentation, in the test.c file in the source repo,
37 and in the wiki on the project's home page.
 
 
38 */
39
40 #if defined(__cplusplus)
41 extern "C" {
42 #endif
@@ -296,10 +296,14 @@
296 @see cson_value_type_id()
297 */
298
299 /** @var cson_rc
300
301 Deprecated: clients are encouraged to use the CSON_RC_xxx values
302 which correspond to cson_rc.xxx, as those are more efficient. Some
303 docs and code may still refer to cson_rc, though.
304
305 This object defines the error codes used by cson.
306
307 Library routines which return int values almost always return a
308 value from this structure. None of the members in this struct have
309 published values except for the OK member, which has the value 0.
@@ -315,14 +319,106 @@
319 if( 0 == rc ) {...success...}
320 else if( cson_rc.ArgError == rc ) { ... some argument was wrong ... }
321 else if( cson_rc.AllocError == rc ) { ... allocation error ... }
322 ...
323 @endcode
324
325 Or with the preferred/newer method:
326
327 @code
328 int rc = cson_some_func(...);
329 switch(rc){
330 case 0: ...success...;
331 case CSON_RC_ArgError: ... some argument was wrong ...
332 case CSON_RC_AllocError: ... allocation error ...
333 ...
334 }
335 @endcode
336
337 The entries named Parse_XXX are generally only returned by
338 cson_parse() and friends.
339
340 @deprecated
341 */
342
343 /**
344 The CSON_RC_xxx values are intended to replace the older
345 cson_rc.xxx values.
346 */
347 enum cson_rc_values {
348 /** The generic success value. Guaranteed to be 0. */
349 CSON_RC_OK = 0,
350 /** Signifies an error in one or more arguments (e.g. NULL where it is not allowed). */
351 CSON_RC_ArgError,
352 /** Signifies that some argument is not in a valid range. */
353 CSON_RC_RangeError,
354 /** Signifies that some argument is not of the correct logical cson type. */
355 CSON_RC_TypeError,
356 /** Signifies an input/ouput error. */
357 CSON_RC_IOError,
358 /** Signifies an out-of-memory error. */
359 CSON_RC_AllocError,
360 /** Signifies that the called code is "NYI" (Not Yet Implemented). */
361 CSON_RC_NYIError,
362 /** Signifies that an internal error was triggered. If it happens, please report this as a bug! */
363 CSON_RC_InternalError,
364 /** Signifies that the called operation is not supported in the
365 current environment. e.g. missing support from 3rd-party or
366 platform-specific code.
367 */
368 CSON_RC_UnsupportedError,
369 /**
370 Signifies that the request resource could not be found.
371 */
372 CSON_RC_NotFoundError,
373 /**
374 Signifies an unknown error, possibly because an underlying
375 3rd-party API produced an error and we have no other reasonable
376 error code to convert it to.
377 */
378 CSON_RC_UnknownError,
379 /**
380 Signifies that the parser found an unexpected character.
381 */
382 CSON_RC_Parse_INVALID_CHAR,
383 /**
384 Signifies that the parser found an invalid keyword (possibly
385 an unquoted string).
386 */
387 CSON_RC_Parse_INVALID_KEYWORD,
388 /**
389 Signifies that the parser found an invalid escape sequence.
390 */
391 CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE,
392 /**
393 Signifies that the parser found an invalid Unicode character
394 sequence.
395 */
396 CSON_RC_Parse_INVALID_UNICODE_SEQUENCE,
397 /**
398 Signifies that the parser found an invalid numeric token.
399 */
400 CSON_RC_Parse_INVALID_NUMBER,
401 /**
402 Signifies that the parser reached its maximum defined
403 parsing depth before finishing the input.
404 */
405 CSON_RC_Parse_NESTING_DEPTH_REACHED,
406 /**
407 Signifies that the parser found an unclosed object or array.
408 */
409 CSON_RC_Parse_UNBALANCED_COLLECTION,
410 /**
411 Signifies that the parser found an key in an unexpected place.
412 */
413 CSON_RC_Parse_EXPECTED_KEY,
414 /**
415 Signifies that the parser expected to find a colon but
416 found none (e.g. between keys and values in an object).
417 */
418 CSON_RC_Parse_EXPECTED_COLON
419 };
420
421 /** @struct cson_rc_
422 See \ref cson_rc for details.
423 */
424 static const struct cson_rc_
@@ -397,30 +493,30 @@
493 Signifies that the parser expected to find a colon but
494 found none (e.g. between keys and values in an object).
495 */
496 const int Parse_EXPECTED_COLON;
497 } cson_rc = {
498 CSON_RC_OK,
499 CSON_RC_ArgError,
500 CSON_RC_RangeError,
501 CSON_RC_TypeError,
502 CSON_RC_IOError,
503 CSON_RC_AllocError,
504 CSON_RC_NYIError,
505 CSON_RC_InternalError,
506 CSON_RC_UnsupportedError,
507 CSON_RC_NotFoundError,
508 CSON_RC_UnknownError,
509 CSON_RC_Parse_INVALID_CHAR,
510 CSON_RC_Parse_INVALID_KEYWORD,
511 CSON_RC_Parse_INVALID_ESCAPE_SEQUENCE,
512 CSON_RC_Parse_INVALID_UNICODE_SEQUENCE,
513 CSON_RC_Parse_INVALID_NUMBER,
514 CSON_RC_Parse_NESTING_DEPTH_REACHED,
515 CSON_RC_Parse_UNBALANCED_COLLECTION,
516 CSON_RC_Parse_EXPECTED_KEY,
517 CSON_RC_Parse_EXPECTED_COLON
518 };
519
520 /**
521 Returns the string form of the cson_rc code corresponding to rc, or
522 some unspecified, non-NULL string if it is an unknown code.
@@ -671,12 +767,12 @@
767 so any output-destination-specific state can be stored there and accessed
768 via the src callback.
769
770 Non-parse error conditions include:
771
772 - (!tgt) or !src: CSON_RC_ArgError
773 - CSON_RC_AllocError can happen at any time during the input phase
774
775 Here's a complete example of using a custom input source:
776
777 @code
778 // Internal type to hold state for a JSON input string.
@@ -692,12 +788,12 @@
788 unsigned int * n )
789 {
790 StringSource * ss = (StringSource*) state;
791 unsigned int i;
792 unsigned char * tgt = (unsigned char *)dest;
793 if( ! ss || ! n || !dest ) return CSON_RC_ArgError;
794 else if( !*n ) return CSON_RC_RangeError;
795 for( i = 0;
796 (i < *n) && (ss->pos < ss->end);
797 ++i, ++ss->pos, ++tgt )
798 {
799 *tgt = *ss->pos;
@@ -748,11 +844,11 @@
844 cson_parse_opt const * opt, cson_parse_info * info );
845
846 /**
847 Convenience wrapper around cson_parse_FILE() which opens the given filename.
848
849 Returns CSON_RC_IOError if the file cannot be opened.
850
851 @see cson_parse_FILE()
852 */
853 int cson_parse_filename( cson_value ** tgt, char const * src,
854 cson_parse_opt const * opt, cson_parse_info * info );
@@ -763,11 +859,11 @@
859
860 src must be a string containing JSON code, at least len bytes long,
861 and the parser will attempt to parse exactly len bytes from src.
862
863 If len is less than 2 (the minimum length of a legal top-node JSON
864 object) then CSON_RC_RangeError is returned.
865 */
866 int cson_parse_string( cson_value ** tgt, char const * src, unsigned int len,
867 cson_parse_opt const * opt, cson_parse_info * info );
868
869
@@ -779,11 +875,11 @@
875
876 If opt is NULL then default options (the values defined in
877 cson_output_opt_empty) are used.
878
879 If opt->maxDepth is exceeded while traversing the value tree,
880 CSON_RC_RangeError is returned.
881
882 The destState parameter is ignored by this function and is passed
883 on to the dest function.
884
885 Returns 0 on success. On error, any amount of output might have been
@@ -816,11 +912,11 @@
912 @see cson_output_filename()
913 */
914 int cson_output_FILE( cson_value const * src, FILE * dest, cson_output_opt const * opt );
915 /**
916 Convenience wrapper around cson_output_FILE() which writes to the given filename, destroying
917 any existing contents. Returns CSON_RC_IOError if the file cannot be opened.
918
919 @see cson_output_FILE()
920 */
921 int cson_output_filename( cson_value const * src, char const * dest, cson_output_opt const * fmt );
922
@@ -947,11 +1043,11 @@
1043 The conversion, if any, depends on the concrete type of val:
1044
1045 NULL, null, undefined: *v is set to 0 and 0 is returned.
1046
1047 string, object, array: *v is set to 0 and
1048 CSON_RC_TypeError is returned. The error may normally be safely
1049 ignored, but it is provided for those wanted to know whether a direct
1050 conversion was possible.
1051
1052 integer: *v is set to the int value and 0 is returned.
1053
@@ -1178,19 +1274,19 @@
1274 changes its logical size, but may pre-allocate space in the
1275 array for storing new (as-yet-unassigned) values.
1276
1277 Returns 0 on success, or non-zero on error:
1278
1279 - If ar is NULL: CSON_RC_ArgError
1280
1281 - If allocation fails: CSON_RC_AllocError
1282 */
1283 int cson_array_reserve( cson_array * ar, unsigned int size );
1284
1285 /**
1286 If ar is not NULL, sets *v (if v is not NULL) to the length of the array
1287 and returns 0. Returns CSON_RC_ArgError if ar is NULL.
1288 */
1289 int cson_array_length_fetch( cson_array const * ar, unsigned int * v );
1290
1291 /**
1292 Simplified form of cson_array_length_fetch() which returns 0 if ar
@@ -1243,16 +1339,16 @@
1339 implementation has slightly different array-preallocation policy
1340 (it grows more eagerly).
1341
1342 Returns 0 on success, non-zero on error. Error cases include:
1343
1344 - ar or v are NULL: CSON_RC_ArgError
1345
1346 - Array cannot be expanded to hold enough elements: CSON_RC_AllocError.
1347
1348 - Appending would cause a numeric overlow in the array's size:
1349 CSON_RC_RangeError. (However, you'll get an AllocError long before
1350 that happens!)
1351
1352 On error ownership of v is NOT modified, and the caller may still
1353 need to clean it up. See cson_array_set() for the details.
1354
@@ -1449,13 +1545,13 @@
1545 show up later, e.g. during output.
1546
1547 Returns 0 on success, non-0 on error. It has the following error
1548 cases:
1549
1550 - CSON_RC_ArgError: obj or key are NULL or strlen(key) is 0.
1551
1552 - CSON_RC_AllocError: an out-of-memory error
1553
1554 On error ownership of v is NOT modified, and the caller may still
1555 need to clean it up. For example, the following code will introduce
1556 a leak if this function fails:
1557
@@ -1500,14 +1596,14 @@
1596
1597 /**
1598 Removes a property from an object.
1599
1600 If obj contains the given key, it is removed and 0 is returned. If
1601 it is not found, CSON_RC_NotFoundError is returned (which can
1602 normally be ignored by client code).
1603
1604 CSON_RC_ArgError is returned if obj or key are NULL or key has
1605 a length of 0.
1606
1607 Returns 0 if the given key is found and removed.
1608
1609 This is functionally equivalent calling
@@ -1563,27 +1659,27 @@
1659 path is a delimited string, where the delimiter is the given
1660 separator character.
1661
1662 This function searches for the given path, starting at the given object
1663 and traversing its properties as the path specifies. If a given part of the
1664 path is not found, then this function fails with CSON_RC_NotFoundError.
1665
1666 If it finds the given path, it returns the value by assiging *tgt
1667 to it. If tgt is NULL then this function has no side-effects but
1668 will return 0 if the given path is found within the object, so it can be used
1669 to test for existence without fetching it.
1670
1671 Returns 0 if it finds an entry, CSON_RC_NotFoundError if it finds
1672 no item, and any other non-zero error code on a "real" error. Errors include:
1673
1674 - obj or path are NULL: CSON_RC_ArgError
1675
1676 - separator is 0, or path is an empty string or contains only
1677 separator characters: CSON_RC_RangeError
1678
1679 - There is an upper limit on how long a single path component may
1680 be (some "reasonable" internal size), and CSON_RC_RangeError is
1681 returned if that length is violated.
1682
1683
1684 Limitations:
1685
@@ -1677,11 +1773,11 @@
1773 either replaced or left as-is, depending on whether flags contains
1774 he CSON_MERGE_REPLACE bit.
1775
1776 Returns 0 on success. The error conditions are:
1777
1778 - dest or src are NULL or (dest==src) returns CSON_RC_ArgError.
1779
1780 - dest or src contain cyclic references - this will likely cause a
1781 crash due to endless recursion.
1782
1783 Potential TODOs:
@@ -1724,11 +1820,11 @@
1820 */
1821 extern const cson_object_iterator cson_object_iterator_empty;
1822
1823 /**
1824 Initializes the given iterator to point at the start of obj's
1825 properties. Returns 0 on success or CSON_RC_ArgError if !obj
1826 or !iter.
1827
1828 obj must outlive iter, or results are undefined. Results are also
1829 undefined if obj is modified while the iterator is active.
1830
@@ -1891,13 +1987,13 @@
1987 to be NULL-terminated. On error the buffer might contain partial
1988 contents, and it should not be used except to free its contents.
1989
1990 On error non-zero is returned. Errors include:
1991
1992 - Invalid arguments: CSON_RC_ArgError
1993
1994 - Buffer cannot be expanded (runs out of memory): CSON_RC_AllocError
1995
1996 Example usage:
1997
1998 @code
1999 cson_buffer buf = cson_buffer_empty;
@@ -1999,13 +2095,13 @@
2095 On error non-0 is returned and dest has almost certainly been
2096 modified but its state must be considered incomplete.
2097
2098 Errors include:
2099
2100 - dest or src are NULL (CSON_RC_ArgError)
2101
2102 - Allocation error (CSON_RC_AllocError)
2103
2104 - src() returns an error code
2105
2106 Whether or not the state parameter may be NULL depends on
2107 the src implementation requirements.
@@ -2084,12 +2180,12 @@
2180 will not be if there are still other live references to
2181 it). cson_value_free() will not _actually_ destroy the value until
2182 its reference count drops to 0.
2183
2184 Returns 0 on success. The only error conditions are if v is NULL
2185 (CSON_RC_ArgError) or if the reference increment would overflow
2186 (CSON_RC_RangeError). In theory a client would get allocation
2187 errors long before the reference count could overflow (assuming
2188 those reference counts come from container insertions, as opposed
2189 to via this function).
2190
2191 Insider notes which clients really need to know:
@@ -2238,11 +2334,11 @@
2334 /**
2335 Calculates the approximate in-memory-allocated size of v,
2336 recursively if it is a container type, with the following caveats
2337 and limitations:
2338
2339 If a given value is reference counted and encountered multiple
2340 times within a traversed container, each reference is counted at
2341 full cost. We have no way of knowing if a given reference has been
2342 visited already and whether it should or should not be counted, so
2343 we pessimistically count them even though the _might_ not really
2344 count for the given object tree (it depends on where the other open
@@ -2318,10 +2414,169 @@
2414 it might contain partial results.
2415 */
2416 int cson_parse_argv_flags( int argc, char const * const * argv,
2417 cson_object ** tgt, unsigned int * count );
2418
2419 /**
2420 Return values for the cson_pack() and cson_unpack() interfaces.
2421 */
2422 enum cson_pack_retval {
2423 /** Signals an out-of-memory error. */
2424 CSON_PACK_ALLOC_ERROR = -1,
2425 /** Signals a syntax error in the format string. */
2426 CSON_PACK_ARG_ERROR = -2,
2427 /**
2428 Signals an that an internal error has occurred.
2429 This indicates a bug in this library.
2430 */
2431 CSON_PACK_INTERNAL_ERROR = -3,
2432 /**
2433 Signals that the JSON document does not validate agains the format
2434 string passed to cson_unpack().
2435 */
2436 CSON_PACK_VALIDATION_ERROR = -4
2437 };
2438
2439 /**
2440 Construct arbitrarily complex JSON documents from native C types.
2441
2442 Create a new object or array and add or merge the passed values and
2443 properties to it according to the supplied format string.
2444
2445 fmt is a format string, it must at least contain an array or object
2446 specifier as its root value. Format specifiers start with a percent sign '\%'
2447 followed by one or more modifiers and a type character. Object properties
2448 are specified as key-value pairs where the key is specified as a string and
2449 passed as an argument of const char *. Any space, tab, carriage return, line
2450 feed, colon and comma characters between format specifiers are ignored.
2451
2452 | Type | Description |
2453 | :--: | :---------- |
2454 | s | creates either a property name or a string value, in case of the former the corresponding argument is a pointer to const char which is a sequence of bytes specifying the name of the property that is to be created, in case of the latter the corresponding argument is a pointer to const char |
2455 | d | creates an integer value, the corresponding argument is an int |
2456 | i | ^ |
2457 | f | creates a floating point value, the corresponding argument is a double |
2458 | b | creates a boolean value, the corresponding argument is an int |
2459 | N | creates a null value |
2460 | [...] | creates an array, the corresponding argument is a pointer to a cson_array |
2461 | {...} | creates an array, the corresponding argument is a pointer to a cson_object |
2462
2463 | Modifier | Description |
2464 | :------: | :---------- |
2465 | l | specifies that the following d or i specifier applies to an argument which is a pointer to long |
2466 | ll | specifies that the following d or i specifier applies to an argument which is a pointer to cson_int_t |
2467
2468 | Short Form | Expands to
2469 | :--------: | :--------- |
2470 | {...} | %*{...} |
2471 | [...] | %*[...] |
2472 | \%D | \%lld |
2473
2474
2475 Returns 0 on success. The error conditions are:
2476
2477 - CSON_PACK_ARG_ERROR: fmt contains a syntax error
2478
2479 - CSON_PACK_ALLOC_ERROR: a memory allocation failed
2480
2481 - CSON_PACK_INTERNAL_ERROR: an internal error has occurred, this is a bug in
2482 cson
2483
2484 Example:
2485 @code
2486 cson_value * root_value;
2487 cson_array * arr;
2488 ...
2489 rc = cson_pack( root_value, "{%s: %d, %s: %[]}", "foo", 42, "bar", arr );
2490 if( 0 != rc ) {
2491 ... error ...
2492 }
2493 @endcode
2494 */
2495 int cson_pack( cson_value **root_valuep, const char *fmt, ... );
2496
2497 /**
2498 Same as cson_pack() except that it takes a va_list instead of a variable
2499 number of arguments.
2500 */
2501 int cson_vpack( cson_value **root_valuep, const char *fmt, va_list args );
2502
2503 /**
2504 Iterate over the given object or array and convert an arbitrary number of
2505 JSON values into their native C types or validates them according to the
2506 given format string fmt.
2507
2508 fmt is a format string, it must at least contain an array or object
2509 specifier as its root value. Format specifiers start with a percent sign '\%'
2510 followed by one or more modifiers and a type character. Object properties
2511 are specified as key-value pairs where the key is specified as a string and
2512 passed as an argument of const char *. Any space, tab, carriage return, line
2513 feed, colon and comma characters between format specifiers are ignored.
2514
2515 | Type | Description |
2516 | :--: | :---------- |
2517 | s | matches a either a property name or a string value, in case of the former the corresponding argument is a pointer to const char which is a sequence of bytes specifying the name of the property that is to be matched, in case of the latter the corresponding argument is a pointer to a pointer to const char unless the 'm' modifier is specified where the the corresponding argument is a pointer to a pointer to char |
2518 | d | matches an integer value and must be used in with the "ll" modifier, the corresponding argument is a pointer to cson_int_t |
2519 | i | ^ |
2520 | f | matches a floating point value, the corresponding argument is a pointer to double |
2521 | b | matches a boolean value, the corresponding argument is a pointer to int |
2522 | N | matches a null value |
2523 | [...] | matches an array, the corresponding argument is a pointer to a pointer to a cson_array |
2524 | {...} | matches an array, the corresponding argument is a pointer to a pointer to a cson_object |
2525
2526 | Modifier | Description |
2527 | :------: | :---------- |
2528 | ? | specifies that the property reffered to by the given property name is optional |
2529 | * | suppresses assignment, only check for the presence and type of the specified value |
2530 | m | allocates a memory buffer for the extracted string |
2531 | ll | specifies that the following d or i specifier applies to an argument which is a pointer to cson_int_t |
2532
2533 | Short Form | Expands to
2534 | :--------: | :--------- |
2535 | {...} | %*{...} |
2536 | [...] | %*[...] |
2537 | \%D | \%lld |
2538
2539 Returns 0 on success. The error conditions are:
2540
2541 - CSON_PACK_ARG_ERROR: fmt contains a syntax error
2542
2543 - CSON_PACK_ALLOC_ERROR: a memory allocation failed
2544
2545 - CSON_PACK_VALIDATION_ERROR: validation failed, the JSON document structure
2546 differs from that described by the format string
2547
2548 - CSON_PACK_INTERNAL_ERROR: an internal error has occurred, this
2549 indicates a bug in this library.
2550
2551 Example:
2552 @code
2553 cson_value * root_value;
2554 cson_int_t x = 0;
2555 cson_array * arr = NULL;
2556 const char *str = NULL;
2557 ...
2558 rc = cson_unpack( root_value, "{%s: %d, %s: %[], %?s: %s}", "foo", &x, "bar", &arr, "baz", &str );
2559 if( rc < 3 && rc >= 0 ) {
2560 ... optional property is missing ...
2561 } else if ( CSON_PACK_ALLOC_ERROR == rc ) {
2562 ... out of memory error ...
2563 } else if ( CSON_PACK_VALIDATION_ERROR == rc ) {
2564 ... unexpected JSON document structure ...
2565 } else if ( rc ) {
2566 ... internal error ...
2567 }
2568 @endcode
2569
2570 */
2571 int cson_unpack( cson_value *root_value, const char *fmt, ... );
2572
2573 /**
2574 Same as cson_unpack() except that it takes a va_list instead of a variable
2575 number of arguments.
2576 */
2577 int cson_vunpack( cson_value *root_value, const char *fmt, va_list args );
2578
2579 /* LICENSE
2580
2581 This software's source code, including accompanying documentation and
2582 demonstration applications, are licensed under the following
@@ -2416,11 +2671,11 @@
2671 #define CSON_ENABLE_SQLITE3 1
2672 # endif
2673 #endif
2674
2675 #if CSON_ENABLE_SQLITE3 /* we do this here for the sake of the amalgamation build */
2676 #include "sqlite3.h"
2677
2678 #if defined(__cplusplus)
2679 extern "C" {
2680 #endif
2681
2682
+773 -153
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -262,10 +262,11 @@
262262
/* Deselect most features from the console I/O package for Fiddle. */
263263
# define SQLITE_CIO_NO_REDIRECT
264264
# define SQLITE_CIO_NO_CLASSIFY
265265
# define SQLITE_CIO_NO_TRANSLATE
266266
# define SQLITE_CIO_NO_SETMODE
267
+# define SQLITE_CIO_NO_FLUSH
267268
#endif
268269
/************************* Begin ../ext/consio/console_io.h ******************/
269270
/*
270271
** 2023 November 1
271272
**
@@ -442,16 +443,23 @@
442443
#ifdef CONSIO_EPUTB
443444
SQLITE_INTERNAL_LINKAGE int
444445
ePutbUtf8(const char *cBuf, int nAccept);
445446
#endif
446447
448
+/*
449
+** Flush the given output stream. Return non-zero for success, else 0.
450
+*/
451
+#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
452
+SQLITE_INTERNAL_LINKAGE int
453
+fFlushBuffer(FILE *pfOut);
454
+#endif
455
+
447456
/*
448457
** Collect input like fgets(...) with special provisions for input
449
-** from the console on platforms that require same. Defers to the
450
-** C library fgets() when input is not from the console. Newline
451
-** translation may be done as set by set{Binary,Text}Mode(). As a
452
-** convenience, pfIn==NULL is treated as stdin.
458
+** from the console on such platforms as require same. Newline
459
+** translation may be done as set by set{Binary,Text}Mode().
460
+** As a convenience, pfIn==NULL is treated as stdin.
453461
*/
454462
SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
455463
/* Like fGetsUtf8 except stream is always the designated input. */
456464
/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
457465
@@ -1144,10 +1152,90 @@
11441152
# if CIO_WIN_WC_XLATE
11451153
}
11461154
# endif
11471155
}
11481156
1157
+/*
1158
+** Flush the given output stream. Return non-zero for success, else 0.
1159
+*/
1160
+#if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
1161
+SQLITE_INTERNAL_LINKAGE int
1162
+fFlushBuffer(FILE *pfOut){
1163
+# if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
1164
+ return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
1165
+# else
1166
+ return fflush(pfOut);
1167
+# endif
1168
+}
1169
+#endif
1170
+
1171
+#if CIO_WIN_WC_XLATE \
1172
+ && !defined(SHELL_OMIT_FIO_DUPE) \
1173
+ && defined(SQLITE_USE_ONLY_WIN32)
1174
+static struct FileAltIds {
1175
+ int fd;
1176
+ HANDLE fh;
1177
+} altIdsOfFile(FILE *pf){
1178
+ struct FileAltIds rv = { _fileno(pf) };
1179
+ union { intptr_t osfh; HANDLE fh; } fid = {
1180
+ (rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
1181
+ };
1182
+ rv.fh = fid.fh;
1183
+ return rv;
1184
+}
1185
+
1186
+SQLITE_INTERNAL_LINKAGE size_t
1187
+cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
1188
+ size_t rv = 0;
1189
+ struct FileAltIds fai = altIdsOfFile(pf);
1190
+ int fmode = _setmode(fai.fd, _O_BINARY);
1191
+ _setmode(fai.fd, fmode);
1192
+ while( rv < ocnt ){
1193
+ size_t nbo = osz;
1194
+ while( nbo > 0 ){
1195
+ DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
1196
+ BOOL wrc = TRUE;
1197
+ BOOL genCR = (fmode & _O_TEXT)!=0;
1198
+ if( genCR ){
1199
+ const char *pnl = (const char*)memchr(buf, '\n', nbo);
1200
+ if( pnl ) nbo = pnl - (const char*)buf;
1201
+ else genCR = 0;
1202
+ }
1203
+ if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
1204
+ if( genCR && wrc ){
1205
+ wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
1206
+ ++dwno; /* Skip over the LF */
1207
+ }
1208
+ if( !wrc ) return rv;
1209
+ buf = (const char*)buf + dwno;
1210
+ nbo += dwno;
1211
+ }
1212
+ ++rv;
1213
+ }
1214
+ return rv;
1215
+}
1216
+
1217
+SQLITE_INTERNAL_LINKAGE char *
1218
+cfGets(char *cBuf, int n, FILE *pf){
1219
+ int nci = 0;
1220
+ struct FileAltIds fai = altIdsOfFile(pf);
1221
+ int fmode = _setmode(fai.fd, _O_BINARY);
1222
+ BOOL eatCR = (fmode & _O_TEXT)!=0;
1223
+ _setmode(fai.fd, fmode);
1224
+ while( nci < n-1 ){
1225
+ DWORD nr;
1226
+ if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
1227
+ if( nr>0 && (!eatCR || cBuf[nci]!='\r') ) nci += nr;
1228
+ }
1229
+ if( nci < n ) cBuf[nci] = 0;
1230
+ return (nci>0)? cBuf : 0;
1231
+}
1232
+# else
1233
+# define cfWrite(b,os,no,f) fwrite(b,os,no,f)
1234
+# define cfGets(b,n,f) fgets(b,n,f)
1235
+# endif
1236
+
11491237
# ifdef CONSIO_EPUTB
11501238
SQLITE_INTERNAL_LINKAGE int
11511239
ePutbUtf8(const char *cBuf, int nAccept){
11521240
FILE *pfErr;
11531241
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
@@ -1155,11 +1243,11 @@
11551243
# if CIO_WIN_WC_XLATE
11561244
if( pstReachesConsole(ppst) ){
11571245
return conZstrEmit(ppst, cBuf, nAccept);
11581246
}else {
11591247
# endif
1160
- return (int)fwrite(cBuf, 1, nAccept, pfErr);
1248
+ return (int)cfWrite(cBuf, 1, nAccept, pfErr);
11611249
# if CIO_WIN_WC_XLATE
11621250
}
11631251
# endif
11641252
}
11651253
# endif /* defined(CONSIO_EPUTB) */
@@ -1221,11 +1309,11 @@
12211309
return cBuf;
12221310
}else return 0;
12231311
# endif
12241312
}else{
12251313
# endif
1226
- return fgets(cBuf, ncMax, pfIn);
1314
+ return cfGets(cBuf, ncMax, pfIn);
12271315
# if CIO_WIN_WC_XLATE
12281316
}
12291317
# endif
12301318
}
12311319
#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
@@ -1265,15 +1353,16 @@
12651353
# define oputz(z) oPutsUtf8(z)
12661354
# define oputf oPrintfUtf8
12671355
# define eputz(z) ePutsUtf8(z)
12681356
# define eputf ePrintfUtf8
12691357
# define oputb(buf,na) oPutbUtf8(buf,na)
1358
+# define fflush(s) fFlushBuffer(s);
12701359
12711360
#else
12721361
/* For Fiddle, all console handling and emit redirection is omitted. */
12731362
/* These next 3 macros are for emitting formatted output. When complaints
1274
- * from the WASM build are issued for non-formatted output, (when a mere
1363
+ * from the WASM build are issued for non-formatted output, when a mere
12751364
* string literal is to be emitted, the ?putz(z) forms should be used.
12761365
* (This permits compile-time checking of format string / argument mismatch.)
12771366
*/
12781367
# define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
12791368
# define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
@@ -1281,10 +1370,11 @@
12811370
/* These next 3 macros are for emitting simple string literals. */
12821371
# define oputz(z) fputs(z,stdout)
12831372
# define eputz(z) fputs(z,stderr)
12841373
# define sputz(fp,z) fputs(z,fp)
12851374
# define oputb(buf,na) fwrite(buf,1,na,stdout)
1375
+# undef fflush
12861376
#endif
12871377
12881378
/* True if the timer is enabled */
12891379
static int enableTimer = 0;
12901380
@@ -1519,10 +1609,18 @@
15191609
size_t i;
15201610
for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
15211611
dest[i] = 0;
15221612
return dest;
15231613
}
1614
+
1615
+/*
1616
+** strcpy() workalike to squelch an unwarranted link-time warning
1617
+** from OpenBSD.
1618
+*/
1619
+static void shell_strcpy(char *dest, const char *src){
1620
+ while( (*(dest++) = *(src++))!=0 ){}
1621
+}
15241622
15251623
/*
15261624
** Optionally disable dynamic continuation prompt.
15271625
** Unless disabled, the continuation prompt shows open SQL lexemes if any,
15281626
** or open parentheses level if non-zero, or continuation prompt as set.
@@ -1585,11 +1683,11 @@
15851683
}else{
15861684
if( dynPrompt.zScannerAwaits ){
15871685
size_t ncp = strlen(continuePrompt);
15881686
size_t ndp = strlen(dynPrompt.zScannerAwaits);
15891687
if( ndp > ncp-3 ) return continuePrompt;
1590
- strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
1688
+ shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
15911689
while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
15921690
shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
15931691
PROMPT_LEN_MAX-4);
15941692
}else{
15951693
if( dynPrompt.inParenLevel>9 ){
@@ -4681,11 +4779,11 @@
46814779
** May you share freely, never taking more than you give.
46824780
**
46834781
******************************************************************************
46844782
**
46854783
** This file contains code to implement the percentile(Y,P) SQL function
4686
-** as described below:
4784
+** and similar as described below:
46874785
**
46884786
** (1) The percentile(Y,P) function is an aggregate function taking
46894787
** exactly two arguments.
46904788
**
46914789
** (2) If the P argument to percentile(Y,P) is not the same for every
@@ -4730,48 +4828,173 @@
47304828
** file that compiles into a shared-library or DLL that can be loaded
47314829
** into SQLite using the sqlite3_load_extension() interface.
47324830
**
47334831
** (13) A separate median(Y) function is the equivalent percentile(Y,50).
47344832
**
4735
-** (14) A separate percentile_cond(Y,X) function is the equivalent of
4736
-** percentile(Y,X*100.0).
4833
+** (14) A separate percentile_cont(Y,P) function is equivalent to
4834
+** percentile(Y,P/100.0). In other words, the fraction value in
4835
+** the second argument is in the range of 0 to 1 instead of 0 to 100.
4836
+**
4837
+** (15) A separate percentile_disc(Y,P) function is like
4838
+** percentile_cont(Y,P) except that instead of returning the weighted
4839
+** average of the nearest two input values, it returns the next lower
4840
+** value. So the percentile_disc(Y,P) will always return a value
4841
+** that was one of the inputs.
4842
+**
4843
+** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and
4844
+** percentile_disc(Y,P) can be used as window functions.
4845
+**
4846
+** Differences from standard SQL:
4847
+**
4848
+** * The percentile_cont(X,P) function is equivalent to the following in
4849
+** standard SQL:
4850
+**
4851
+** (percentile_cont(P) WITHIN GROUP (ORDER BY X))
4852
+**
4853
+** The SQLite syntax is much more compact. The standard SQL syntax
4854
+** is also supported if SQLite is compiled with the
4855
+** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option.
4856
+**
4857
+** * No median(X) function exists in the SQL standard. App developers
4858
+** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)".
4859
+**
4860
+** * No percentile(Y,P) function exists in the SQL standard. Instead of
4861
+** percential(Y,P), developers must write this:
4862
+** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that
4863
+** the fraction parameter to percentile() goes from 0 to 100 whereas
4864
+** the fraction parameter in SQL standard percentile_cont() goes from
4865
+** 0 to 1.
4866
+**
4867
+** Implementation notes as of 2024-08-31:
4868
+**
4869
+** * The regular aggregate-function versions of these routines work
4870
+** by accumulating all values in an array of doubles, then sorting
4871
+** that array using quicksort before computing the answer. Thus
4872
+** the runtime is O(NlogN) where N is the number of rows of input.
4873
+**
4874
+** * For the window-function versions of these routines, the array of
4875
+** inputs is sorted as soon as the first value is computed. Thereafter,
4876
+** the array is kept in sorted order using an insert-sort. This
4877
+** results in O(N*K) performance where K is the size of the window.
4878
+** One can imagine alternative implementations that give O(N*logN*logK)
4879
+** performance, but they require more complex logic and data structures.
4880
+** The developers have elected to keep the asymptotically slower
4881
+** algorithm for now, for simplicity, under the theory that window
4882
+** functions are seldom used and when they are, the window size K is
4883
+** often small. The developers might revisit that decision later,
4884
+** should the need arise.
47374885
*/
4738
-/* #include "sqlite3ext.h" */
4739
-SQLITE_EXTENSION_INIT1
4886
+#if defined(SQLITE3_H)
4887
+ /* no-op */
4888
+#elif defined(SQLITE_STATIC_PERCENTILE)
4889
+/* # include "sqlite3.h" */
4890
+#else
4891
+/* # include "sqlite3ext.h" */
4892
+ SQLITE_EXTENSION_INIT1
4893
+#endif
47404894
#include <assert.h>
47414895
#include <string.h>
47424896
#include <stdlib.h>
47434897
4744
-/* The following object is the session context for a single percentile()
4745
-** function. We have to remember all input Y values until the very end.
4898
+/* The following object is the group context for a single percentile()
4899
+** aggregate. Remember all input Y values until the very end.
47464900
** Those values are accumulated in the Percentile.a[] array.
47474901
*/
47484902
typedef struct Percentile Percentile;
47494903
struct Percentile {
47504904
unsigned nAlloc; /* Number of slots allocated for a[] */
47514905
unsigned nUsed; /* Number of slots actually used in a[] */
4752
- double rPct; /* 1.0 more than the value for P */
4906
+ char bSorted; /* True if a[] is already in sorted order */
4907
+ char bKeepSorted; /* True if advantageous to keep a[] sorted */
4908
+ char bPctValid; /* True if rPct is valid */
4909
+ double rPct; /* Fraction. 0.0 to 1.0 */
47534910
double *a; /* Array of Y values */
47544911
};
4912
+
4913
+/* Details of each function in the percentile family */
4914
+typedef struct PercentileFunc PercentileFunc;
4915
+struct PercentileFunc {
4916
+ const char *zName; /* Function name */
4917
+ char nArg; /* Number of arguments */
4918
+ char mxFrac; /* Maximum value of the "fraction" input */
4919
+ char bDiscrete; /* True for percentile_disc() */
4920
+};
4921
+static const PercentileFunc aPercentFunc[] = {
4922
+ { "median", 1, 1, 0 },
4923
+ { "percentile", 2, 100, 0 },
4924
+ { "percentile_cont", 2, 1, 0 },
4925
+ { "percentile_disc", 2, 1, 1 },
4926
+};
47554927
47564928
/*
47574929
** Return TRUE if the input floating-point number is an infinity.
47584930
*/
4759
-static int isInfinity(double r){
4931
+static int percentIsInfinity(double r){
47604932
sqlite3_uint64 u;
47614933
assert( sizeof(u)==sizeof(r) );
47624934
memcpy(&u, &r, sizeof(u));
47634935
return ((u>>52)&0x7ff)==0x7ff;
47644936
}
47654937
47664938
/*
4767
-** Return TRUE if two doubles differ by 0.001 or less
4939
+** Return TRUE if two doubles differ by 0.001 or less.
47684940
*/
4769
-static int sameValue(double a, double b){
4941
+static int percentSameValue(double a, double b){
47704942
a -= b;
47714943
return a>=-0.001 && a<=0.001;
47724944
}
4945
+
4946
+/*
4947
+** Search p (which must have p->bSorted) looking for an entry with
4948
+** value y. Return the index of that entry.
4949
+**
4950
+** If bExact is true, return -1 if the entry is not found.
4951
+**
4952
+** If bExact is false, return the index at which a new entry with
4953
+** value y should be insert in order to keep the values in sorted
4954
+** order. The smallest return value in this case will be 0, and
4955
+** the largest return value will be p->nUsed.
4956
+*/
4957
+static int percentBinarySearch(Percentile *p, double y, int bExact){
4958
+ int iFirst = 0; /* First element of search range */
4959
+ int iLast = p->nUsed - 1; /* Last element of search range */
4960
+ while( iLast>=iFirst ){
4961
+ int iMid = (iFirst+iLast)/2;
4962
+ double x = p->a[iMid];
4963
+ if( x<y ){
4964
+ iFirst = iMid + 1;
4965
+ }else if( x>y ){
4966
+ iLast = iMid - 1;
4967
+ }else{
4968
+ return iMid;
4969
+ }
4970
+ }
4971
+ if( bExact ) return -1;
4972
+ return iFirst;
4973
+}
4974
+
4975
+/*
4976
+** Generate an error for a percentile function.
4977
+**
4978
+** The error format string must have exactly one occurrance of "%%s()"
4979
+** (with two '%' characters). That substring will be replaced by the name
4980
+** of the function.
4981
+*/
4982
+static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){
4983
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
4984
+ char *zMsg1;
4985
+ char *zMsg2;
4986
+ va_list ap;
4987
+
4988
+ va_start(ap, zFormat);
4989
+ zMsg1 = sqlite3_vmprintf(zFormat, ap);
4990
+ va_end(ap);
4991
+ zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, pFunc->zName) : 0;
4992
+ sqlite3_result_error(pCtx, zMsg2, -1);
4993
+ sqlite3_free(zMsg1);
4994
+ sqlite3_free(zMsg2);
4995
+}
47734996
47744997
/*
47754998
** The "step" function for percentile(Y,P) is called once for each
47764999
** input row.
47775000
*/
@@ -4782,45 +5005,38 @@
47825005
double y;
47835006
assert( argc==2 || argc==1 );
47845007
47855008
if( argc==1 ){
47865009
/* Requirement 13: median(Y) is the same as percentile(Y,50). */
4787
- rPct = 50.0;
4788
- }else if( sqlite3_user_data(pCtx)==0 ){
4789
- /* Requirement 3: P must be a number between 0 and 100 */
4790
- eType = sqlite3_value_numeric_type(argv[1]);
4791
- rPct = sqlite3_value_double(argv[1]);
4792
- if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
4793
- || rPct<0.0 || rPct>100.0 ){
4794
- sqlite3_result_error(pCtx, "2nd argument to percentile() is not "
4795
- "a number between 0.0 and 100.0", -1);
4796
- return;
4797
- }
4798
- }else{
4799
- /* Requirement 3: P must be a number between 0 and 1 */
4800
- eType = sqlite3_value_numeric_type(argv[1]);
4801
- rPct = sqlite3_value_double(argv[1]);
4802
- if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
4803
- || rPct<0.0 || rPct>1.0 ){
4804
- sqlite3_result_error(pCtx, "2nd argument to percentile_cont() is not "
4805
- "a number between 0.0 and 1.0", -1);
4806
- return;
4807
- }
4808
- rPct *= 100.0;
5010
+ rPct = 0.5;
5011
+ }else{
5012
+ /* Requirement 3: P must be a number between 0 and 100 */
5013
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
5014
+ eType = sqlite3_value_numeric_type(argv[1]);
5015
+ rPct = sqlite3_value_double(argv[1])/(double)pFunc->mxFrac;
5016
+ if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
5017
+ || rPct<0.0 || rPct>1.0
5018
+ ){
5019
+ percentError(pCtx, "the fraction argument to %%s()"
5020
+ " is not between 0.0 and %.1f",
5021
+ (double)pFunc->mxFrac);
5022
+ return;
5023
+ }
48095024
}
48105025
48115026
/* Allocate the session context. */
48125027
p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
48135028
if( p==0 ) return;
48145029
48155030
/* Remember the P value. Throw an error if the P value is different
48165031
** from any prior row, per Requirement (2). */
4817
- if( p->rPct==0.0 ){
4818
- p->rPct = rPct+1.0;
4819
- }else if( !sameValue(p->rPct,rPct+1.0) ){
4820
- sqlite3_result_error(pCtx, "2nd argument to percentile() is not the "
4821
- "same for all input rows", -1);
5032
+ if( !p->bPctValid ){
5033
+ p->rPct = rPct;
5034
+ p->bPctValid = 1;
5035
+ }else if( !percentSameValue(p->rPct,rPct) ){
5036
+ percentError(pCtx, "the fraction argument to %%s()"
5037
+ " is not the same for all input rows");
48225038
return;
48235039
}
48245040
48255041
/* Ignore rows for which Y is NULL */
48265042
eType = sqlite3_value_type(argv[0]);
@@ -4827,19 +5043,18 @@
48275043
if( eType==SQLITE_NULL ) return;
48285044
48295045
/* If not NULL, then Y must be numeric. Otherwise throw an error.
48305046
** Requirement 4 */
48315047
if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
4832
- sqlite3_result_error(pCtx, "1st argument to percentile() is not "
4833
- "numeric", -1);
5048
+ percentError(pCtx, "input to %%s() is not numeric");
48345049
return;
48355050
}
48365051
48375052
/* Throw an error if the Y value is infinity or NaN */
48385053
y = sqlite3_value_double(argv[0]);
4839
- if( isInfinity(y) ){
4840
- sqlite3_result_error(pCtx, "Inf input to percentile()", -1);
5054
+ if( percentIsInfinity(y) ){
5055
+ percentError(pCtx, "Inf input to %%s()");
48415056
return;
48425057
}
48435058
48445059
/* Allocate and store the Y */
48455060
if( p->nUsed>=p->nAlloc ){
@@ -4852,112 +5067,209 @@
48525067
return;
48535068
}
48545069
p->nAlloc = n;
48555070
p->a = a;
48565071
}
4857
- p->a[p->nUsed++] = y;
5072
+ if( p->nUsed==0 ){
5073
+ p->a[p->nUsed++] = y;
5074
+ p->bSorted = 1;
5075
+ }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
5076
+ p->a[p->nUsed++] = y;
5077
+ }else if( p->bKeepSorted ){
5078
+ int i;
5079
+ i = percentBinarySearch(p, y, 0);
5080
+ if( i<p->nUsed ){
5081
+ memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
5082
+ }
5083
+ p->a[i] = y;
5084
+ p->nUsed++;
5085
+ }else{
5086
+ p->a[p->nUsed++] = y;
5087
+ p->bSorted = 0;
5088
+ }
48585089
}
48595090
5091
+/*
5092
+** Interchange two doubles.
5093
+*/
5094
+#define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;}
5095
+
48605096
/*
48615097
** Sort an array of doubles.
5098
+**
5099
+** Algorithm: quicksort
5100
+**
5101
+** This is implemented separately rather than using the qsort() routine
5102
+** from the standard library because:
5103
+**
5104
+** (1) To avoid a dependency on qsort()
5105
+** (2) To avoid the function call to the comparison routine for each
5106
+** comparison.
48625107
*/
4863
-static void sortDoubles(double *a, int n){
4864
- int iLt; /* Entries with index less than iLt are less than rPivot */
4865
- int iGt; /* Entries with index iGt or more are greater than rPivot */
5108
+static void percentSort(double *a, unsigned int n){
5109
+ int iLt; /* Entries before a[iLt] are less than rPivot */
5110
+ int iGt; /* Entries at or after a[iGt] are greater than rPivot */
48665111
int i; /* Loop counter */
48675112
double rPivot; /* The pivot value */
4868
- double rTmp; /* Temporary used to swap two values */
4869
-
4870
- if( n<2 ) return;
4871
- if( n>5 ){
4872
- rPivot = (a[0] + a[n/2] + a[n-1])/3.0;
4873
- }else{
4874
- rPivot = a[n/2];
4875
- }
4876
- iLt = i = 0;
4877
- iGt = n;
4878
- while( i<iGt ){
5113
+
5114
+ assert( n>=2 );
5115
+ if( a[0]>a[n-1] ){
5116
+ SWAP_DOUBLE(a[0],a[n-1])
5117
+ }
5118
+ if( n==2 ) return;
5119
+ iGt = n-1;
5120
+ i = n/2;
5121
+ if( a[0]>a[i] ){
5122
+ SWAP_DOUBLE(a[0],a[i])
5123
+ }else if( a[i]>a[iGt] ){
5124
+ SWAP_DOUBLE(a[i],a[iGt])
5125
+ }
5126
+ if( n==3 ) return;
5127
+ rPivot = a[i];
5128
+ iLt = i = 1;
5129
+ do{
48795130
if( a[i]<rPivot ){
4880
- if( i>iLt ){
4881
- rTmp = a[i];
4882
- a[i] = a[iLt];
4883
- a[iLt] = rTmp;
4884
- }
5131
+ if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
48855132
iLt++;
48865133
i++;
48875134
}else if( a[i]>rPivot ){
48885135
do{
48895136
iGt--;
48905137
}while( iGt>i && a[iGt]>rPivot );
4891
- rTmp = a[i];
4892
- a[i] = a[iGt];
4893
- a[iGt] = rTmp;
5138
+ SWAP_DOUBLE(a[i],a[iGt])
48945139
}else{
48955140
i++;
48965141
}
4897
- }
4898
- if( iLt>=2 ) sortDoubles(a, iLt);
4899
- if( n-iGt>=2 ) sortDoubles(a+iGt, n-iGt);
4900
-
5142
+ }while( i<iGt );
5143
+ if( iLt>=2 ) percentSort(a, iLt);
5144
+ if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
5145
+
49015146
/* Uncomment for testing */
49025147
#if 0
49035148
for(i=0; i<n-1; i++){
49045149
assert( a[i]<=a[i+1] );
49055150
}
49065151
#endif
49075152
}
5153
+
49085154
49095155
/*
4910
-** Called to compute the final output of percentile() and to clean
4911
-** up all allocated memory.
5156
+** The "inverse" function for percentile(Y,P) is called to remove a
5157
+** row that was previously inserted by "step".
49125158
*/
4913
-static void percentFinal(sqlite3_context *pCtx){
5159
+static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){
5160
+ Percentile *p;
5161
+ int eType;
5162
+ double y;
5163
+ int i;
5164
+ assert( argc==2 || argc==1 );
5165
+
5166
+ /* Allocate the session context. */
5167
+ p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
5168
+ assert( p!=0 );
5169
+
5170
+ /* Ignore rows for which Y is NULL */
5171
+ eType = sqlite3_value_type(argv[0]);
5172
+ if( eType==SQLITE_NULL ) return;
5173
+
5174
+ /* If not NULL, then Y must be numeric. Otherwise throw an error.
5175
+ ** Requirement 4 */
5176
+ if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
5177
+ return;
5178
+ }
5179
+
5180
+ /* Ignore the Y value if it is infinity or NaN */
5181
+ y = sqlite3_value_double(argv[0]);
5182
+ if( percentIsInfinity(y) ){
5183
+ return;
5184
+ }
5185
+ if( p->bSorted==0 ){
5186
+ assert( p->nUsed>1 );
5187
+ percentSort(p->a, p->nUsed);
5188
+ p->bSorted = 1;
5189
+ }
5190
+ p->bKeepSorted = 1;
5191
+
5192
+ /* Find and remove the row */
5193
+ i = percentBinarySearch(p, y, 1);
5194
+ if( i>=0 ){
5195
+ p->nUsed--;
5196
+ if( i<p->nUsed ){
5197
+ memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
5198
+ }
5199
+ }
5200
+}
5201
+
5202
+/*
5203
+** Compute the final output of percentile(). Clean up all allocated
5204
+** memory if and only if bIsFinal is true.
5205
+*/
5206
+static void percentCompute(sqlite3_context *pCtx, int bIsFinal){
49145207
Percentile *p;
5208
+ PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
49155209
unsigned i1, i2;
49165210
double v1, v2;
49175211
double ix, vx;
49185212
p = (Percentile*)sqlite3_aggregate_context(pCtx, 0);
49195213
if( p==0 ) return;
49205214
if( p->a==0 ) return;
49215215
if( p->nUsed ){
4922
- sortDoubles(p->a, p->nUsed);
4923
- ix = (p->rPct-1.0)*(p->nUsed-1)*0.01;
5216
+ if( p->bSorted==0 ){
5217
+ assert( p->nUsed>1 );
5218
+ percentSort(p->a, p->nUsed);
5219
+ p->bSorted = 1;
5220
+ }
5221
+ ix = p->rPct*(p->nUsed-1);
49245222
i1 = (unsigned)ix;
4925
- i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
4926
- v1 = p->a[i1];
4927
- v2 = p->a[i2];
4928
- vx = v1 + (v2-v1)*(ix-i1);
5223
+ if( pFunc->bDiscrete ){
5224
+ vx = p->a[i1];
5225
+ }else{
5226
+ i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
5227
+ v1 = p->a[i1];
5228
+ v2 = p->a[i2];
5229
+ vx = v1 + (v2-v1)*(ix-i1);
5230
+ }
49295231
sqlite3_result_double(pCtx, vx);
49305232
}
4931
- sqlite3_free(p->a);
4932
- memset(p, 0, sizeof(*p));
5233
+ if( bIsFinal ){
5234
+ sqlite3_free(p->a);
5235
+ memset(p, 0, sizeof(*p));
5236
+ }else{
5237
+ p->bKeepSorted = 1;
5238
+ }
5239
+}
5240
+static void percentFinal(sqlite3_context *pCtx){
5241
+ percentCompute(pCtx, 1);
5242
+}
5243
+static void percentValue(sqlite3_context *pCtx){
5244
+ percentCompute(pCtx, 0);
49335245
}
49345246
4935
-
4936
-#ifdef _WIN32
5247
+#if defined(_WIN32) && !defined(SQLITE3_H) && !defined(SQLITE_STATIC_PERCENTILE)
49375248
49385249
#endif
49395250
int sqlite3_percentile_init(
49405251
sqlite3 *db,
49415252
char **pzErrMsg,
49425253
const sqlite3_api_routines *pApi
49435254
){
49445255
int rc = SQLITE_OK;
5256
+ int i;
5257
+#if defined(SQLITE3_H) || defined(SQLITE_STATIC_PERCENTILE)
5258
+ (void)pApi; /* Unused parameter */
5259
+#else
49455260
SQLITE_EXTENSION_INIT2(pApi);
5261
+#endif
49465262
(void)pzErrMsg; /* Unused parameter */
4947
- rc = sqlite3_create_function(db, "percentile", 2,
4948
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
4949
- 0, percentStep, percentFinal);
4950
- if( rc==SQLITE_OK ){
4951
- rc = sqlite3_create_function(db, "median", 1,
4952
- SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
4953
- 0, percentStep, percentFinal);
4954
- }
4955
- if( rc==SQLITE_OK ){
4956
- rc = sqlite3_create_function(db, "percentile_cont", 2,
4957
- SQLITE_UTF8|SQLITE_INNOCUOUS, &percentStep,
4958
- 0, percentStep, percentFinal);
5263
+ for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
5264
+ rc = sqlite3_create_window_function(db,
5265
+ aPercentFunc[i].zName,
5266
+ aPercentFunc[i].nArg,
5267
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_SELFORDER1,
5268
+ (void*)&aPercentFunc[i],
5269
+ percentStep, percentFinal, percentValue, percentInverse, 0);
5270
+ if( rc ) break;
49595271
}
49605272
return rc;
49615273
}
49625274
49635275
/************************* End ../ext/misc/percentile.c ********************/
@@ -6132,10 +6444,30 @@
61326444
** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step.
61336445
** xBestIndex returns a small cost when both start and stop are available,
61346446
** and a very large cost if either start or stop are unavailable. This
61356447
** encourages the query planner to order joins such that the bounds of the
61366448
** series are well-defined.
6449
+**
6450
+** Update on 2024-08-22:
6451
+** xBestIndex now also looks for equality and inequality constraints against
6452
+** the value column and uses those constraints as additional bounds against
6453
+** the sequence range. Thus, a query like this:
6454
+**
6455
+** SELECT value FROM generate_series($SA,$EA)
6456
+** WHERE value BETWEEN $SB AND $EB;
6457
+**
6458
+** Is logically the same as:
6459
+**
6460
+** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB));
6461
+**
6462
+** Constraints on the value column can server as substitutes for constraints
6463
+** on the hidden start and stop columns. So, the following two queries
6464
+** are equivalent:
6465
+**
6466
+** SELECT value FROM generate_series($S,$E);
6467
+** SELECT value FROM generate_series WHERE value BETWEEN $S and $E;
6468
+**
61376469
*/
61386470
/* #include "sqlite3ext.h" */
61396471
SQLITE_EXTENSION_INIT1
61406472
#include <assert.h>
61416473
#include <string.h>
@@ -6173,12 +6505,14 @@
61736505
}
61746506
61756507
/* typedef unsigned char u8; */
61766508
61776509
typedef struct SequenceSpec {
6178
- sqlite3_int64 iBase; /* Starting value ("start") */
6179
- sqlite3_int64 iTerm; /* Given terminal value ("stop") */
6510
+ sqlite3_int64 iOBase; /* Original starting value ("start") */
6511
+ sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
6512
+ sqlite3_int64 iBase; /* Starting value to actually use */
6513
+ sqlite3_int64 iTerm; /* Terminal value to actually use */
61806514
sqlite3_int64 iStep; /* Increment ("step") */
61816515
sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
61826516
sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
61836517
sqlite3_int64 iValueNow; /* Current value during generation */
61846518
u8 isNotEOF; /* Sequence generation not exhausted */
@@ -6367,21 +6701,23 @@
63676701
int i /* Which column to return */
63686702
){
63696703
series_cursor *pCur = (series_cursor*)cur;
63706704
sqlite3_int64 x = 0;
63716705
switch( i ){
6372
- case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
6373
- case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
6374
- case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
6706
+ case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
6707
+ case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
6708
+ case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
63756709
default: x = pCur->ss.iValueNow; break;
63766710
}
63776711
sqlite3_result_int64(ctx, x);
63786712
return SQLITE_OK;
63796713
}
63806714
63816715
#ifndef LARGEST_UINT64
6716
+#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
63826717
#define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
6718
+#define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
63836719
#endif
63846720
63856721
/*
63866722
** Return the rowid for the current row, logically equivalent to n+1 where
63876723
** "n" is the ascending integer in the aforesaid production definition.
@@ -6418,17 +6754,22 @@
64186754
**
64196755
** The query plan selected by seriesBestIndex is passed in the idxNum
64206756
** parameter. (idxStr is not used in this implementation.) idxNum
64216757
** is a bitmask showing which constraints are available:
64226758
**
6423
-** 0x01: start=VALUE
6424
-** 0x02: stop=VALUE
6425
-** 0x04: step=VALUE
6426
-** 0x08: descending order
6427
-** 0x10: ascending order
6428
-** 0x20: LIMIT VALUE
6429
-** 0x40: OFFSET VALUE
6759
+** 0x0001: start=VALUE
6760
+** 0x0002: stop=VALUE
6761
+** 0x0004: step=VALUE
6762
+** 0x0008: descending order
6763
+** 0x0010: ascending order
6764
+** 0x0020: LIMIT VALUE
6765
+** 0x0040: OFFSET VALUE
6766
+** 0x0080: value=VALUE
6767
+** 0x0100: value>=VALUE
6768
+** 0x0200: value>VALUE
6769
+** 0x1000: value<=VALUE
6770
+** 0x2000: value<VALUE
64306771
**
64316772
** This routine should initialize the cursor and position it so that it
64326773
** is pointing at the first row, or pointing off the end of the table
64336774
** (so that seriesEof() will return true) if the table is empty.
64346775
*/
@@ -6437,10 +6778,16 @@
64376778
int idxNum, const char *idxStrUnused,
64386779
int argc, sqlite3_value **argv
64396780
){
64406781
series_cursor *pCur = (series_cursor *)pVtabCursor;
64416782
int i = 0;
6783
+ int returnNoRows = 0;
6784
+ sqlite3_int64 iMin = SMALLEST_INT64;
6785
+ sqlite3_int64 iMax = LARGEST_INT64;
6786
+ sqlite3_int64 iLimit = 0;
6787
+ sqlite3_int64 iOffset = 0;
6788
+
64426789
(void)idxStrUnused;
64436790
if( idxNum & 0x01 ){
64446791
pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
64456792
}else{
64466793
pCur->ss.iBase = 0;
@@ -6458,38 +6805,125 @@
64586805
if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
64596806
}
64606807
}else{
64616808
pCur->ss.iStep = 1;
64626809
}
6810
+
6811
+ /* If there are constraints on the value column but there are
6812
+ ** no constraints on the start, stop, and step columns, then
6813
+ ** initialize the default range to be the entire range of 64-bit signed
6814
+ ** integers. This range will contracted by the value column constraints
6815
+ ** further below.
6816
+ */
6817
+ if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
6818
+ pCur->ss.iBase = SMALLEST_INT64;
6819
+ }
6820
+ if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
6821
+ pCur->ss.iTerm = LARGEST_INT64;
6822
+ }
6823
+ pCur->ss.iOBase = pCur->ss.iBase;
6824
+ pCur->ss.iOTerm = pCur->ss.iTerm;
6825
+
6826
+ /* Extract the LIMIT and OFFSET values, but do not apply them yet.
6827
+ ** The range must first be constrained by the limits on value.
6828
+ */
64636829
if( idxNum & 0x20 ){
6464
- sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]);
6465
- sqlite3_int64 iTerm;
6830
+ iLimit = sqlite3_value_int64(argv[i++]);
64666831
if( idxNum & 0x40 ){
6467
- sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]);
6468
- if( iOffset>0 ){
6469
- pCur->ss.iBase += pCur->ss.iStep*iOffset;
6832
+ iOffset = sqlite3_value_int64(argv[i++]);
6833
+ }
6834
+ }
6835
+
6836
+ if( idxNum & 0x3380 ){
6837
+ /* Extract the maximum range of output values determined by
6838
+ ** constraints on the "value" column.
6839
+ */
6840
+ if( idxNum & 0x0080 ){
6841
+ iMin = iMax = sqlite3_value_int64(argv[i++]);
6842
+ }else{
6843
+ if( idxNum & 0x0300 ){
6844
+ iMin = sqlite3_value_int64(argv[i++]);
6845
+ if( idxNum & 0x0200 ){
6846
+ if( iMin==LARGEST_INT64 ){
6847
+ returnNoRows = 1;
6848
+ }else{
6849
+ iMin++;
6850
+ }
6851
+ }
64706852
}
6853
+ if( idxNum & 0x3000 ){
6854
+ iMax = sqlite3_value_int64(argv[i++]);
6855
+ if( idxNum & 0x2000 ){
6856
+ if( iMax==SMALLEST_INT64 ){
6857
+ returnNoRows = 1;
6858
+ }else{
6859
+ iMax--;
6860
+ }
6861
+ }
6862
+ }
6863
+ if( iMin>iMax ){
6864
+ returnNoRows = 1;
6865
+ }
6866
+ }
6867
+
6868
+ /* Try to reduce the range of values to be generated based on
6869
+ ** constraints on the "value" column.
6870
+ */
6871
+ if( pCur->ss.iStep>0 ){
6872
+ sqlite3_int64 szStep = pCur->ss.iStep;
6873
+ if( pCur->ss.iBase<iMin ){
6874
+ sqlite3_uint64 d = iMin - pCur->ss.iBase;
6875
+ pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
6876
+ }
6877
+ if( pCur->ss.iTerm>iMax ){
6878
+ sqlite3_uint64 d = pCur->ss.iTerm - iMax;
6879
+ pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
6880
+ }
6881
+ }else{
6882
+ sqlite3_int64 szStep = -pCur->ss.iStep;
6883
+ assert( szStep>0 );
6884
+ if( pCur->ss.iBase>iMax ){
6885
+ sqlite3_uint64 d = pCur->ss.iBase - iMax;
6886
+ pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
6887
+ }
6888
+ if( pCur->ss.iTerm<iMin ){
6889
+ sqlite3_uint64 d = iMin - pCur->ss.iTerm;
6890
+ pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
6891
+ }
6892
+ }
6893
+ }
6894
+
6895
+ /* Apply LIMIT and OFFSET constraints, if any */
6896
+ if( idxNum & 0x20 ){
6897
+ if( iOffset>0 ){
6898
+ pCur->ss.iBase += pCur->ss.iStep*iOffset;
64716899
}
64726900
if( iLimit>=0 ){
6901
+ sqlite3_int64 iTerm;
64736902
iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
64746903
if( pCur->ss.iStep<0 ){
64756904
if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
64766905
}else{
64776906
if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
64786907
}
64796908
}
64806909
}
6910
+
6911
+
64816912
for(i=0; i<argc; i++){
64826913
if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
64836914
/* If any of the constraints have a NULL value, then return no rows.
64846915
** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
6485
- pCur->ss.iBase = 1;
6486
- pCur->ss.iTerm = 0;
6487
- pCur->ss.iStep = 1;
6916
+ returnNoRows = 1;
64886917
break;
64896918
}
64906919
}
6920
+ if( returnNoRows ){
6921
+ pCur->ss.iBase = 1;
6922
+ pCur->ss.iTerm = 0;
6923
+ pCur->ss.iStep = 1;
6924
+ }
64916925
if( idxNum & 0x08 ){
64926926
pCur->ss.isReversing = pCur->ss.iStep > 0;
64936927
}else{
64946928
pCur->ss.isReversing = pCur->ss.iStep < 0;
64956929
}
@@ -6506,17 +6940,39 @@
65066940
** In this implementation idxNum is used to represent the
65076941
** query plan. idxStr is unused.
65086942
**
65096943
** The query plan is represented by bits in idxNum:
65106944
**
6511
-** 0x01 start = $value -- constraint exists
6512
-** 0x02 stop = $value -- constraint exists
6513
-** 0x04 step = $value -- constraint exists
6514
-** 0x08 output is in descending order
6515
-** 0x10 output is in ascending order
6516
-** 0x20 LIMIT $value -- constraint exists
6517
-** 0x40 OFFSET $value -- constraint exists
6945
+** 0x0001 start = $num
6946
+** 0x0002 stop = $num
6947
+** 0x0004 step = $num
6948
+** 0x0008 output is in descending order
6949
+** 0x0010 output is in ascending order
6950
+** 0x0020 LIMIT $num
6951
+** 0x0040 OFFSET $num
6952
+** 0x0080 value = $num
6953
+** 0x0100 value >= $num
6954
+** 0x0200 value > $num
6955
+** 0x1000 value <= $num
6956
+** 0x2000 value < $num
6957
+**
6958
+** Only one of 0x0100 or 0x0200 will be returned. Similarly, only
6959
+** one of 0x1000 or 0x2000 will be returned. If the 0x0080 is set, then
6960
+** none of the 0xff00 bits will be set.
6961
+**
6962
+** The order of parameters passed to xFilter is as follows:
6963
+**
6964
+** * The argument to start= if bit 0x0001 is in the idxNum mask
6965
+** * The argument to stop= if bit 0x0002 is in the idxNum mask
6966
+** * The argument to step= if bit 0x0004 is in the idxNum mask
6967
+** * The argument to LIMIT if bit 0x0020 is in the idxNum mask
6968
+** * The argument to OFFSET if bit 0x0040 is in the idxNum mask
6969
+** * The argument to value=, or value>= or value> if any of
6970
+** bits 0x0380 are in the idxNum mask
6971
+** * The argument to value<= or value< if either of bits 0x3000
6972
+** are in the mask
6973
+**
65186974
*/
65196975
static int seriesBestIndex(
65206976
sqlite3_vtab *pVTab,
65216977
sqlite3_index_info *pIdxInfo
65226978
){
@@ -6525,19 +6981,21 @@
65256981
#ifndef ZERO_ARGUMENT_GENERATE_SERIES
65266982
int bStartSeen = 0; /* EQ constraint seen on the START column */
65276983
#endif
65286984
int unusableMask = 0; /* Mask of unusable constraints */
65296985
int nArg = 0; /* Number of arguments that seriesFilter() expects */
6530
- int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */
6986
+ int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
6987
+ ** and value. aIdx[5] covers value=, value>=, and
6988
+ ** value>, aIdx[6] covers value<= and value< */
65316989
const struct sqlite3_index_constraint *pConstraint;
65326990
65336991
/* This implementation assumes that the start, stop, and step columns
65346992
** are the last three columns in the virtual table. */
65356993
assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
65366994
assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
65376995
6538
- aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1;
6996
+ aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = aIdx[5] = aIdx[6] = -1;
65396997
pConstraint = pIdxInfo->aConstraint;
65406998
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
65416999
int iCol; /* 0 for start, 1 for stop, 2 for step */
65427000
int iMask; /* bitmask for those column */
65437001
int op = pConstraint->op;
@@ -6554,11 +7012,54 @@
65547012
aIdx[4] = i;
65557013
idxNum |= 0x40;
65567014
}
65577015
continue;
65587016
}
6559
- if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
7017
+ if( pConstraint->iColumn==SERIES_COLUMN_VALUE ){
7018
+ switch( op ){
7019
+ case SQLITE_INDEX_CONSTRAINT_EQ:
7020
+ case SQLITE_INDEX_CONSTRAINT_IS: {
7021
+ idxNum |= 0x0080;
7022
+ idxNum &= ~0x3300;
7023
+ aIdx[5] = i;
7024
+ aIdx[6] = -1;
7025
+ bStartSeen = 1;
7026
+ break;
7027
+ }
7028
+ case SQLITE_INDEX_CONSTRAINT_GE: {
7029
+ if( idxNum & 0x0080 ) break;
7030
+ idxNum |= 0x0100;
7031
+ idxNum &= ~0x0200;
7032
+ aIdx[5] = i;
7033
+ bStartSeen = 1;
7034
+ break;
7035
+ }
7036
+ case SQLITE_INDEX_CONSTRAINT_GT: {
7037
+ if( idxNum & 0x0080 ) break;
7038
+ idxNum |= 0x0200;
7039
+ idxNum &= ~0x0100;
7040
+ aIdx[5] = i;
7041
+ bStartSeen = 1;
7042
+ break;
7043
+ }
7044
+ case SQLITE_INDEX_CONSTRAINT_LE: {
7045
+ if( idxNum & 0x0080 ) break;
7046
+ idxNum |= 0x1000;
7047
+ idxNum &= ~0x2000;
7048
+ aIdx[6] = i;
7049
+ break;
7050
+ }
7051
+ case SQLITE_INDEX_CONSTRAINT_LT: {
7052
+ if( idxNum & 0x0080 ) break;
7053
+ idxNum |= 0x2000;
7054
+ idxNum &= ~0x1000;
7055
+ aIdx[6] = i;
7056
+ break;
7057
+ }
7058
+ }
7059
+ continue;
7060
+ }
65607061
iCol = pConstraint->iColumn - SERIES_COLUMN_START;
65617062
assert( iCol>=0 && iCol<=2 );
65627063
iMask = 1 << iCol;
65637064
#ifndef ZERO_ARGUMENT_GENERATE_SERIES
65647065
if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){
@@ -6576,11 +7077,11 @@
65767077
if( aIdx[3]==0 ){
65777078
/* Ignore OFFSET if LIMIT is omitted */
65787079
idxNum &= ~0x60;
65797080
aIdx[4] = 0;
65807081
}
6581
- for(i=0; i<5; i++){
7082
+ for(i=0; i<7; i++){
65827083
if( (j = aIdx[i])>=0 ){
65837084
pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
65847085
pIdxInfo->aConstraintUsage[j].omit =
65857086
!SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3;
65867087
}
@@ -6624,10 +7125,13 @@
66247125
** of numbers. Make this case very expensive so that the query
66257126
** planner will work hard to avoid it. */
66267127
pIdxInfo->estimatedRows = 2147483647;
66277128
}
66287129
pIdxInfo->idxNum = idxNum;
7130
+#ifdef SQLITE_INDEX_SCAN_HEX
7131
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_HEX;
7132
+#endif
66297133
return SQLITE_OK;
66307134
}
66317135
66327136
/*
66337137
** This following structure defines all the methods for the
@@ -22175,14 +22679,15 @@
2217522679
sqlite3_bind_double(pStmt, i, INFINITY);
2217622680
#endif
2217722681
}else if( strncmp(zVar, "$int_", 5)==0 ){
2217822682
sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
2217922683
}else if( strncmp(zVar, "$text_", 6)==0 ){
22180
- char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
22684
+ size_t szVar = strlen(zVar);
22685
+ char *zBuf = sqlite3_malloc64( szVar-5 );
2218122686
if( zBuf ){
22182
- memcpy(zBuf, &zVar[6], strlen(zVar)-5);
22183
- sqlite3_bind_text64(pStmt, i, zBuf, -1, sqlite3_free, SQLITE_UTF8);
22687
+ memcpy(zBuf, &zVar[6], szVar-5);
22688
+ sqlite3_bind_text64(pStmt, i, zBuf, szVar-6, sqlite3_free, SQLITE_UTF8);
2218422689
}
2218522690
}else{
2218622691
sqlite3_bind_null(pStmt, i);
2218722692
}
2218822693
sqlite3_reset(pQ);
@@ -24970,16 +25475,21 @@
2497025475
oputf("%-20s %u\n", "data version", iDataVersion);
2497125476
return 0;
2497225477
}
2497325478
#endif /* SQLITE_SHELL_HAVE_RECOVER */
2497425479
25480
+/*
25481
+** Print the given string as an error message.
25482
+*/
25483
+static void shellEmitError(const char *zErr){
25484
+ eputf("Error: %s\n", zErr);
25485
+}
2497525486
/*
2497625487
** Print the current sqlite3_errmsg() value to stderr and return 1.
2497725488
*/
2497825489
static int shellDatabaseError(sqlite3 *db){
24979
- const char *zErr = sqlite3_errmsg(db);
24980
- eputf("Error: %s\n", zErr);
25490
+ shellEmitError(sqlite3_errmsg(db));
2498125491
return 1;
2498225492
}
2498325493
2498425494
/*
2498525495
** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
@@ -25520,11 +26030,11 @@
2552026030
va_list ap;
2552126031
char *z;
2552226032
va_start(ap, zFmt);
2552326033
z = sqlite3_vmprintf(zFmt, ap);
2552426034
va_end(ap);
25525
- eputf("Error: %s\n", z);
26035
+ shellEmitError(z);
2552626036
if( pAr->fromCmdLine ){
2552726037
eputz("Use \"-A\" for more help\n");
2552826038
}else{
2552926039
eputz("Use \".archive --help\" for more help\n");
2553026040
}
@@ -26751,20 +27261,20 @@
2675127261
0, 0, 0);
2675227262
}
2675327263
open_db(p, 0);
2675427264
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
2675527265
if( pBackup==0 ){
26756
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
27266
+ shellDatabaseError(pDest);
2675727267
close_db(pDest);
2675827268
return 1;
2675927269
}
2676027270
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
2676127271
sqlite3_backup_finish(pBackup);
2676227272
if( rc==SQLITE_DONE ){
2676327273
rc = 0;
2676427274
}else{
26765
- eputf("Error: %s\n", sqlite3_errmsg(pDest));
27275
+ shellDatabaseError(pDest);
2676627276
rc = 1;
2676727277
}
2676827278
close_db(pDest);
2676927279
}else
2677027280
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -26936,11 +27446,11 @@
2693627446
sqlite3_stmt *pStmt;
2693727447
int i;
2693827448
open_db(p, 0);
2693927449
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
2694027450
if( rc ){
26941
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
27451
+ shellDatabaseError(p->db);
2694227452
rc = 1;
2694327453
}else{
2694427454
while( sqlite3_step(pStmt)==SQLITE_ROW ){
2694527455
const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
2694627456
const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
@@ -27632,11 +28142,11 @@
2763228142
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2763328143
sqlite3_free(zSql);
2763428144
zSql = 0;
2763528145
if( rc ){
2763628146
if (pStmt) sqlite3_finalize(pStmt);
27637
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
28147
+ shellDatabaseError(p->db);
2763828148
import_cleanup(&sCtx);
2763928149
rc = 1;
2764028150
goto meta_command_exit;
2764128151
}
2764228152
if( sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -27676,11 +28186,11 @@
2767628186
}
2767728187
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
2767828188
sqlite3_free(zSql);
2767928189
zSql = 0;
2768028190
if( rc ){
27681
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
28191
+ shellDatabaseError(p->db);
2768228192
if (pStmt) sqlite3_finalize(pStmt);
2768328193
import_cleanup(&sCtx);
2768428194
rc = 1;
2768528195
goto meta_command_exit;
2768628196
}
@@ -27970,11 +28480,11 @@
2797028480
zFile = azArg[1];
2797128481
zProc = nArg>=3 ? azArg[2] : 0;
2797228482
open_db(p, 0);
2797328483
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
2797428484
if( rc!=SQLITE_OK ){
27975
- eputf("Error: %s\n", zErrMsg);
28485
+ shellEmitError(zErrMsg);
2797628486
sqlite3_free(zErrMsg);
2797728487
rc = 1;
2797828488
}
2797928489
}else
2798028490
#endif
@@ -28592,11 +29102,11 @@
2859229102
return 1;
2859329103
}
2859429104
open_db(p, 0);
2859529105
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
2859629106
if( pBackup==0 ){
28597
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
29107
+ shellDatabaseError(p->db);
2859829108
close_db(pSrc);
2859929109
return 1;
2860029110
}
2860129111
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
2860229112
|| rc==SQLITE_BUSY ){
@@ -28610,11 +29120,11 @@
2861029120
rc = 0;
2861129121
}else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
2861229122
eputz("Error: source database is busy\n");
2861329123
rc = 1;
2861429124
}else{
28615
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
29125
+ shellDatabaseError(p->db);
2861629126
rc = 1;
2861729127
}
2861829128
close_db(pSrc);
2861929129
}else
2862029130
#endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -28707,11 +29217,11 @@
2870729217
if( zDiv ){
2870829218
sqlite3_stmt *pStmt = 0;
2870929219
rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
2871029220
-1, &pStmt, 0);
2871129221
if( rc ){
28712
- eputf("Error: %s\n", sqlite3_errmsg(p->db));
29222
+ shellDatabaseError(p->db);
2871329223
sqlite3_finalize(pStmt);
2871429224
rc = 1;
2871529225
goto meta_command_exit;
2871629226
}
2871729227
appendText(&sSelect, "SELECT sql FROM", 0);
@@ -28776,11 +29286,11 @@
2877629286
rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
2877729287
}
2877829288
freeText(&sSelect);
2877929289
}
2878029290
if( zErrMsg ){
28781
- eputf("Error: %s\n", zErrMsg);
29291
+ shellEmitError(zErrMsg);
2878229292
sqlite3_free(zErrMsg);
2878329293
rc = 1;
2878429294
}else if( rc != SQLITE_OK ){
2878529295
eputz("Error: querying schema information\n");
2878629296
rc = 1;
@@ -29547,11 +30057,11 @@
2954730057
{"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
2954830058
{"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
2954930059
{"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
2955030060
{"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
2955130061
{"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
29552
- {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
30062
+ {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK ..."},
2955330063
#ifdef YYCOVERAGE
2955430064
{"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
2955530065
#endif
2955630066
{"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,1, "OFFSET " },
2955730067
{"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
@@ -29610,13 +30120,123 @@
2961030120
if( testctrl<0 ){
2961130121
eputf("Error: unknown test-control: %s\n"
2961230122
"Use \".testctrl --help\" for help\n", zCmd);
2961330123
}else{
2961430124
switch(testctrl){
30125
+
30126
+ /* Special processing for .testctrl opt MASK ...
30127
+ ** Each MASK argument can be one of:
30128
+ **
30129
+ ** +LABEL Enable the named optimization
30130
+ **
30131
+ ** -LABEL Disable the named optimization
30132
+ **
30133
+ ** INTEGER Mask of optimizations to disable
30134
+ */
30135
+ case SQLITE_TESTCTRL_OPTIMIZATIONS: {
30136
+ static const struct {
30137
+ unsigned int mask; /* Mask for this optimization */
30138
+ unsigned int bDsply; /* Display this on output */
30139
+ const char *zLabel; /* Name of optimization */
30140
+ } aLabel[] = {
30141
+ { 0x00000001, 1, "QueryFlattener" },
30142
+ { 0x00000001, 0, "Flatten" },
30143
+ { 0x00000002, 1, "WindowFunc" },
30144
+ { 0x00000004, 1, "GroupByOrder" },
30145
+ { 0x00000008, 1, "FactorOutConst" },
30146
+ { 0x00000010, 1, "DistinctOpt" },
30147
+ { 0x00000020, 1, "CoverIdxScan" },
30148
+ { 0x00000040, 1, "OrderByIdxJoin" },
30149
+ { 0x00000080, 1, "Transitive" },
30150
+ { 0x00000100, 1, "OmitNoopJoin" },
30151
+ { 0x00000200, 1, "CountOfView" },
30152
+ { 0x00000400, 1, "CurosrHints" },
30153
+ { 0x00000800, 1, "Stat4" },
30154
+ { 0x00001000, 1, "PushDown" },
30155
+ { 0x00002000, 1, "SimplifyJoin" },
30156
+ { 0x00004000, 1, "SkipScan" },
30157
+ { 0x00008000, 1, "PropagateConst" },
30158
+ { 0x00010000, 1, "MinMaxOpt" },
30159
+ { 0x00020000, 1, "SeekScan" },
30160
+ { 0x00040000, 1, "OmitOrderBy" },
30161
+ { 0x00080000, 1, "BloomFilter" },
30162
+ { 0x00100000, 1, "BloomPulldown" },
30163
+ { 0x00200000, 1, "BalancedMerge" },
30164
+ { 0x00400000, 1, "ReleaseReg" },
30165
+ { 0x00800000, 1, "FlttnUnionAll" },
30166
+ { 0x01000000, 1, "IndexedEXpr" },
30167
+ { 0x02000000, 1, "Coroutines" },
30168
+ { 0x04000000, 1, "NullUnusedCols" },
30169
+ { 0x08000000, 1, "OnePass" },
30170
+ { 0x10000000, 1, "OrderBySubq" },
30171
+ { 0xffffffff, 0, "All" },
30172
+ };
30173
+ unsigned int curOpt;
30174
+ unsigned int newOpt;
30175
+ int ii;
30176
+ sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
30177
+ newOpt = curOpt;
30178
+ for(ii=2; ii<nArg; ii++){
30179
+ const char *z = azArg[ii];
30180
+ int useLabel = 0;
30181
+ const char *zLabel = 0;
30182
+ if( (z[0]=='+'|| z[0]=='-') && !IsDigit(z[1]) ){
30183
+ useLabel = z[0];
30184
+ zLabel = &z[1];
30185
+ }else if( !IsDigit(z[0]) && z[0]!=0 && !IsDigit(z[1]) ){
30186
+ useLabel = '+';
30187
+ zLabel = z;
30188
+ }else{
30189
+ newOpt = (unsigned int)strtol(z,0,0);
30190
+ }
30191
+ if( useLabel ){
30192
+ int jj;
30193
+ for(jj=0; jj<ArraySize(aLabel); jj++){
30194
+ if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
30195
+ }
30196
+ if( jj>=ArraySize(aLabel) ){
30197
+ eputf("Error: no such optimization: \"%s\"\n", zLabel);
30198
+ eputz("Should be one of:");
30199
+ for(jj=0; jj<ArraySize(aLabel); jj++){
30200
+ eputf(" %s", aLabel[jj].zLabel);
30201
+ }
30202
+ eputz("\n");
30203
+ rc = 1;
30204
+ goto meta_command_exit;
30205
+ }
30206
+ if( useLabel=='+' ){
30207
+ newOpt &= ~aLabel[jj].mask;
30208
+ }else{
30209
+ newOpt |= aLabel[jj].mask;
30210
+ }
30211
+ }
30212
+ }
30213
+ if( curOpt!=newOpt ){
30214
+ sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
30215
+ }else if( nArg<3 ){
30216
+ curOpt = ~newOpt;
30217
+ }
30218
+ if( newOpt==0 ){
30219
+ oputz("+All\n");
30220
+ }else if( newOpt==0xffffffff ){
30221
+ oputz("-All\n");
30222
+ }else{
30223
+ int jj;
30224
+ for(jj=0; jj<ArraySize(aLabel); jj++){
30225
+ unsigned int m = aLabel[jj].mask;
30226
+ if( !aLabel[jj].bDsply ) continue;
30227
+ if( (curOpt&m)!=(newOpt&m) ){
30228
+ oputf("%c%s\n", (newOpt & m)==0 ? '+' : '-',
30229
+ aLabel[jj].zLabel);
30230
+ }
30231
+ }
30232
+ }
30233
+ rc2 = isOk = 3;
30234
+ break;
30235
+ }
2961530236
2961630237
/* sqlite3_test_control(int, db, int) */
29617
- case SQLITE_TESTCTRL_OPTIMIZATIONS:
2961830238
case SQLITE_TESTCTRL_FK_NO_ACTION:
2961930239
if( nArg==3 ){
2962030240
unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
2962130241
rc2 = sqlite3_test_control(testctrl, p->db, opt);
2962230242
isOk = 3;
@@ -31355,11 +31975,11 @@
3135531975
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
3135631976
}else{
3135731977
open_db(&data, 0);
3135831978
rc = shell_exec(&data, z, &zErrMsg);
3135931979
if( zErrMsg!=0 ){
31360
- eputf("Error: %s\n", zErrMsg);
31980
+ shellEmitError(zErrMsg);
3136131981
if( bail_on_error ) return rc!=0 ? rc : 1;
3136231982
}else if( rc!=0 ){
3136331983
eputf("Error: unable to process SQL \"%s\"\n", z);
3136431984
if( bail_on_error ) return rc;
3136531985
}
@@ -31409,11 +32029,11 @@
3140932029
open_db(&data, 0);
3141032030
echo_group_input(&data, azCmd[i]);
3141132031
rc = shell_exec(&data, azCmd[i], &zErrMsg);
3141232032
if( zErrMsg || rc ){
3141332033
if( zErrMsg!=0 ){
31414
- eputf("Error: %s\n", zErrMsg);
32034
+ shellEmitError(zErrMsg);
3141532035
}else{
3141632036
eputf("Error: unable to process SQL: %s\n", azCmd[i]);
3141732037
}
3141832038
sqlite3_free(zErrMsg);
3141932039
if( rc==0 ) rc = 1;
3142032040
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -262,10 +262,11 @@
262 /* Deselect most features from the console I/O package for Fiddle. */
263 # define SQLITE_CIO_NO_REDIRECT
264 # define SQLITE_CIO_NO_CLASSIFY
265 # define SQLITE_CIO_NO_TRANSLATE
266 # define SQLITE_CIO_NO_SETMODE
 
267 #endif
268 /************************* Begin ../ext/consio/console_io.h ******************/
269 /*
270 ** 2023 November 1
271 **
@@ -442,16 +443,23 @@
442 #ifdef CONSIO_EPUTB
443 SQLITE_INTERNAL_LINKAGE int
444 ePutbUtf8(const char *cBuf, int nAccept);
445 #endif
446
 
 
 
 
 
 
 
 
447 /*
448 ** Collect input like fgets(...) with special provisions for input
449 ** from the console on platforms that require same. Defers to the
450 ** C library fgets() when input is not from the console. Newline
451 ** translation may be done as set by set{Binary,Text}Mode(). As a
452 ** convenience, pfIn==NULL is treated as stdin.
453 */
454 SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
455 /* Like fGetsUtf8 except stream is always the designated input. */
456 /* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
457
@@ -1144,10 +1152,90 @@
1144 # if CIO_WIN_WC_XLATE
1145 }
1146 # endif
1147 }
1148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1149 # ifdef CONSIO_EPUTB
1150 SQLITE_INTERNAL_LINKAGE int
1151 ePutbUtf8(const char *cBuf, int nAccept){
1152 FILE *pfErr;
1153 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
@@ -1155,11 +1243,11 @@
1155 # if CIO_WIN_WC_XLATE
1156 if( pstReachesConsole(ppst) ){
1157 return conZstrEmit(ppst, cBuf, nAccept);
1158 }else {
1159 # endif
1160 return (int)fwrite(cBuf, 1, nAccept, pfErr);
1161 # if CIO_WIN_WC_XLATE
1162 }
1163 # endif
1164 }
1165 # endif /* defined(CONSIO_EPUTB) */
@@ -1221,11 +1309,11 @@
1221 return cBuf;
1222 }else return 0;
1223 # endif
1224 }else{
1225 # endif
1226 return fgets(cBuf, ncMax, pfIn);
1227 # if CIO_WIN_WC_XLATE
1228 }
1229 # endif
1230 }
1231 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
@@ -1265,15 +1353,16 @@
1265 # define oputz(z) oPutsUtf8(z)
1266 # define oputf oPrintfUtf8
1267 # define eputz(z) ePutsUtf8(z)
1268 # define eputf ePrintfUtf8
1269 # define oputb(buf,na) oPutbUtf8(buf,na)
 
1270
1271 #else
1272 /* For Fiddle, all console handling and emit redirection is omitted. */
1273 /* These next 3 macros are for emitting formatted output. When complaints
1274 * from the WASM build are issued for non-formatted output, (when a mere
1275 * string literal is to be emitted, the ?putz(z) forms should be used.
1276 * (This permits compile-time checking of format string / argument mismatch.)
1277 */
1278 # define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
1279 # define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
@@ -1281,10 +1370,11 @@
1281 /* These next 3 macros are for emitting simple string literals. */
1282 # define oputz(z) fputs(z,stdout)
1283 # define eputz(z) fputs(z,stderr)
1284 # define sputz(fp,z) fputs(z,fp)
1285 # define oputb(buf,na) fwrite(buf,1,na,stdout)
 
1286 #endif
1287
1288 /* True if the timer is enabled */
1289 static int enableTimer = 0;
1290
@@ -1519,10 +1609,18 @@
1519 size_t i;
1520 for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
1521 dest[i] = 0;
1522 return dest;
1523 }
 
 
 
 
 
 
 
 
1524
1525 /*
1526 ** Optionally disable dynamic continuation prompt.
1527 ** Unless disabled, the continuation prompt shows open SQL lexemes if any,
1528 ** or open parentheses level if non-zero, or continuation prompt as set.
@@ -1585,11 +1683,11 @@
1585 }else{
1586 if( dynPrompt.zScannerAwaits ){
1587 size_t ncp = strlen(continuePrompt);
1588 size_t ndp = strlen(dynPrompt.zScannerAwaits);
1589 if( ndp > ncp-3 ) return continuePrompt;
1590 strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
1591 while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
1592 shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
1593 PROMPT_LEN_MAX-4);
1594 }else{
1595 if( dynPrompt.inParenLevel>9 ){
@@ -4681,11 +4779,11 @@
4681 ** May you share freely, never taking more than you give.
4682 **
4683 ******************************************************************************
4684 **
4685 ** This file contains code to implement the percentile(Y,P) SQL function
4686 ** as described below:
4687 **
4688 ** (1) The percentile(Y,P) function is an aggregate function taking
4689 ** exactly two arguments.
4690 **
4691 ** (2) If the P argument to percentile(Y,P) is not the same for every
@@ -4730,48 +4828,173 @@
4730 ** file that compiles into a shared-library or DLL that can be loaded
4731 ** into SQLite using the sqlite3_load_extension() interface.
4732 **
4733 ** (13) A separate median(Y) function is the equivalent percentile(Y,50).
4734 **
4735 ** (14) A separate percentile_cond(Y,X) function is the equivalent of
4736 ** percentile(Y,X*100.0).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4737 */
4738 /* #include "sqlite3ext.h" */
4739 SQLITE_EXTENSION_INIT1
 
 
 
 
 
 
4740 #include <assert.h>
4741 #include <string.h>
4742 #include <stdlib.h>
4743
4744 /* The following object is the session context for a single percentile()
4745 ** function. We have to remember all input Y values until the very end.
4746 ** Those values are accumulated in the Percentile.a[] array.
4747 */
4748 typedef struct Percentile Percentile;
4749 struct Percentile {
4750 unsigned nAlloc; /* Number of slots allocated for a[] */
4751 unsigned nUsed; /* Number of slots actually used in a[] */
4752 double rPct; /* 1.0 more than the value for P */
 
 
 
4753 double *a; /* Array of Y values */
4754 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4755
4756 /*
4757 ** Return TRUE if the input floating-point number is an infinity.
4758 */
4759 static int isInfinity(double r){
4760 sqlite3_uint64 u;
4761 assert( sizeof(u)==sizeof(r) );
4762 memcpy(&u, &r, sizeof(u));
4763 return ((u>>52)&0x7ff)==0x7ff;
4764 }
4765
4766 /*
4767 ** Return TRUE if two doubles differ by 0.001 or less
4768 */
4769 static int sameValue(double a, double b){
4770 a -= b;
4771 return a>=-0.001 && a<=0.001;
4772 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4773
4774 /*
4775 ** The "step" function for percentile(Y,P) is called once for each
4776 ** input row.
4777 */
@@ -4782,45 +5005,38 @@
4782 double y;
4783 assert( argc==2 || argc==1 );
4784
4785 if( argc==1 ){
4786 /* Requirement 13: median(Y) is the same as percentile(Y,50). */
4787 rPct = 50.0;
4788 }else if( sqlite3_user_data(pCtx)==0 ){
4789 /* Requirement 3: P must be a number between 0 and 100 */
4790 eType = sqlite3_value_numeric_type(argv[1]);
4791 rPct = sqlite3_value_double(argv[1]);
4792 if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
4793 || rPct<0.0 || rPct>100.0 ){
4794 sqlite3_result_error(pCtx, "2nd argument to percentile() is not "
4795 "a number between 0.0 and 100.0", -1);
4796 return;
4797 }
4798 }else{
4799 /* Requirement 3: P must be a number between 0 and 1 */
4800 eType = sqlite3_value_numeric_type(argv[1]);
4801 rPct = sqlite3_value_double(argv[1]);
4802 if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
4803 || rPct<0.0 || rPct>1.0 ){
4804 sqlite3_result_error(pCtx, "2nd argument to percentile_cont() is not "
4805 "a number between 0.0 and 1.0", -1);
4806 return;
4807 }
4808 rPct *= 100.0;
4809 }
4810
4811 /* Allocate the session context. */
4812 p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
4813 if( p==0 ) return;
4814
4815 /* Remember the P value. Throw an error if the P value is different
4816 ** from any prior row, per Requirement (2). */
4817 if( p->rPct==0.0 ){
4818 p->rPct = rPct+1.0;
4819 }else if( !sameValue(p->rPct,rPct+1.0) ){
4820 sqlite3_result_error(pCtx, "2nd argument to percentile() is not the "
4821 "same for all input rows", -1);
 
4822 return;
4823 }
4824
4825 /* Ignore rows for which Y is NULL */
4826 eType = sqlite3_value_type(argv[0]);
@@ -4827,19 +5043,18 @@
4827 if( eType==SQLITE_NULL ) return;
4828
4829 /* If not NULL, then Y must be numeric. Otherwise throw an error.
4830 ** Requirement 4 */
4831 if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
4832 sqlite3_result_error(pCtx, "1st argument to percentile() is not "
4833 "numeric", -1);
4834 return;
4835 }
4836
4837 /* Throw an error if the Y value is infinity or NaN */
4838 y = sqlite3_value_double(argv[0]);
4839 if( isInfinity(y) ){
4840 sqlite3_result_error(pCtx, "Inf input to percentile()", -1);
4841 return;
4842 }
4843
4844 /* Allocate and store the Y */
4845 if( p->nUsed>=p->nAlloc ){
@@ -4852,112 +5067,209 @@
4852 return;
4853 }
4854 p->nAlloc = n;
4855 p->a = a;
4856 }
4857 p->a[p->nUsed++] = y;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4858 }
4859
 
 
 
 
 
4860 /*
4861 ** Sort an array of doubles.
 
 
 
 
 
 
 
 
 
4862 */
4863 static void sortDoubles(double *a, int n){
4864 int iLt; /* Entries with index less than iLt are less than rPivot */
4865 int iGt; /* Entries with index iGt or more are greater than rPivot */
4866 int i; /* Loop counter */
4867 double rPivot; /* The pivot value */
4868 double rTmp; /* Temporary used to swap two values */
4869
4870 if( n<2 ) return;
4871 if( n>5 ){
4872 rPivot = (a[0] + a[n/2] + a[n-1])/3.0;
4873 }else{
4874 rPivot = a[n/2];
4875 }
4876 iLt = i = 0;
4877 iGt = n;
4878 while( i<iGt ){
 
 
 
 
 
 
4879 if( a[i]<rPivot ){
4880 if( i>iLt ){
4881 rTmp = a[i];
4882 a[i] = a[iLt];
4883 a[iLt] = rTmp;
4884 }
4885 iLt++;
4886 i++;
4887 }else if( a[i]>rPivot ){
4888 do{
4889 iGt--;
4890 }while( iGt>i && a[iGt]>rPivot );
4891 rTmp = a[i];
4892 a[i] = a[iGt];
4893 a[iGt] = rTmp;
4894 }else{
4895 i++;
4896 }
4897 }
4898 if( iLt>=2 ) sortDoubles(a, iLt);
4899 if( n-iGt>=2 ) sortDoubles(a+iGt, n-iGt);
4900
4901 /* Uncomment for testing */
4902 #if 0
4903 for(i=0; i<n-1; i++){
4904 assert( a[i]<=a[i+1] );
4905 }
4906 #endif
4907 }
 
4908
4909 /*
4910 ** Called to compute the final output of percentile() and to clean
4911 ** up all allocated memory.
4912 */
4913 static void percentFinal(sqlite3_context *pCtx){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4914 Percentile *p;
 
4915 unsigned i1, i2;
4916 double v1, v2;
4917 double ix, vx;
4918 p = (Percentile*)sqlite3_aggregate_context(pCtx, 0);
4919 if( p==0 ) return;
4920 if( p->a==0 ) return;
4921 if( p->nUsed ){
4922 sortDoubles(p->a, p->nUsed);
4923 ix = (p->rPct-1.0)*(p->nUsed-1)*0.01;
 
 
 
 
4924 i1 = (unsigned)ix;
4925 i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
4926 v1 = p->a[i1];
4927 v2 = p->a[i2];
4928 vx = v1 + (v2-v1)*(ix-i1);
 
 
 
 
4929 sqlite3_result_double(pCtx, vx);
4930 }
4931 sqlite3_free(p->a);
4932 memset(p, 0, sizeof(*p));
 
 
 
 
 
 
 
 
 
 
4933 }
4934
4935
4936 #ifdef _WIN32
4937
4938 #endif
4939 int sqlite3_percentile_init(
4940 sqlite3 *db,
4941 char **pzErrMsg,
4942 const sqlite3_api_routines *pApi
4943 ){
4944 int rc = SQLITE_OK;
 
 
 
 
4945 SQLITE_EXTENSION_INIT2(pApi);
 
4946 (void)pzErrMsg; /* Unused parameter */
4947 rc = sqlite3_create_function(db, "percentile", 2,
4948 SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
4949 0, percentStep, percentFinal);
4950 if( rc==SQLITE_OK ){
4951 rc = sqlite3_create_function(db, "median", 1,
4952 SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
4953 0, percentStep, percentFinal);
4954 }
4955 if( rc==SQLITE_OK ){
4956 rc = sqlite3_create_function(db, "percentile_cont", 2,
4957 SQLITE_UTF8|SQLITE_INNOCUOUS, &percentStep,
4958 0, percentStep, percentFinal);
4959 }
4960 return rc;
4961 }
4962
4963 /************************* End ../ext/misc/percentile.c ********************/
@@ -6132,10 +6444,30 @@
6132 ** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step.
6133 ** xBestIndex returns a small cost when both start and stop are available,
6134 ** and a very large cost if either start or stop are unavailable. This
6135 ** encourages the query planner to order joins such that the bounds of the
6136 ** series are well-defined.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6137 */
6138 /* #include "sqlite3ext.h" */
6139 SQLITE_EXTENSION_INIT1
6140 #include <assert.h>
6141 #include <string.h>
@@ -6173,12 +6505,14 @@
6173 }
6174
6175 /* typedef unsigned char u8; */
6176
6177 typedef struct SequenceSpec {
6178 sqlite3_int64 iBase; /* Starting value ("start") */
6179 sqlite3_int64 iTerm; /* Given terminal value ("stop") */
 
 
6180 sqlite3_int64 iStep; /* Increment ("step") */
6181 sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
6182 sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
6183 sqlite3_int64 iValueNow; /* Current value during generation */
6184 u8 isNotEOF; /* Sequence generation not exhausted */
@@ -6367,21 +6701,23 @@
6367 int i /* Which column to return */
6368 ){
6369 series_cursor *pCur = (series_cursor*)cur;
6370 sqlite3_int64 x = 0;
6371 switch( i ){
6372 case SERIES_COLUMN_START: x = pCur->ss.iBase; break;
6373 case SERIES_COLUMN_STOP: x = pCur->ss.iTerm; break;
6374 case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
6375 default: x = pCur->ss.iValueNow; break;
6376 }
6377 sqlite3_result_int64(ctx, x);
6378 return SQLITE_OK;
6379 }
6380
6381 #ifndef LARGEST_UINT64
 
6382 #define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
 
6383 #endif
6384
6385 /*
6386 ** Return the rowid for the current row, logically equivalent to n+1 where
6387 ** "n" is the ascending integer in the aforesaid production definition.
@@ -6418,17 +6754,22 @@
6418 **
6419 ** The query plan selected by seriesBestIndex is passed in the idxNum
6420 ** parameter. (idxStr is not used in this implementation.) idxNum
6421 ** is a bitmask showing which constraints are available:
6422 **
6423 ** 0x01: start=VALUE
6424 ** 0x02: stop=VALUE
6425 ** 0x04: step=VALUE
6426 ** 0x08: descending order
6427 ** 0x10: ascending order
6428 ** 0x20: LIMIT VALUE
6429 ** 0x40: OFFSET VALUE
 
 
 
 
 
6430 **
6431 ** This routine should initialize the cursor and position it so that it
6432 ** is pointing at the first row, or pointing off the end of the table
6433 ** (so that seriesEof() will return true) if the table is empty.
6434 */
@@ -6437,10 +6778,16 @@
6437 int idxNum, const char *idxStrUnused,
6438 int argc, sqlite3_value **argv
6439 ){
6440 series_cursor *pCur = (series_cursor *)pVtabCursor;
6441 int i = 0;
 
 
 
 
 
 
6442 (void)idxStrUnused;
6443 if( idxNum & 0x01 ){
6444 pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
6445 }else{
6446 pCur->ss.iBase = 0;
@@ -6458,38 +6805,125 @@
6458 if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
6459 }
6460 }else{
6461 pCur->ss.iStep = 1;
6462 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6463 if( idxNum & 0x20 ){
6464 sqlite3_int64 iLimit = sqlite3_value_int64(argv[i++]);
6465 sqlite3_int64 iTerm;
6466 if( idxNum & 0x40 ){
6467 sqlite3_int64 iOffset = sqlite3_value_int64(argv[i++]);
6468 if( iOffset>0 ){
6469 pCur->ss.iBase += pCur->ss.iStep*iOffset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6470 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6471 }
6472 if( iLimit>=0 ){
 
6473 iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
6474 if( pCur->ss.iStep<0 ){
6475 if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
6476 }else{
6477 if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
6478 }
6479 }
6480 }
 
 
6481 for(i=0; i<argc; i++){
6482 if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
6483 /* If any of the constraints have a NULL value, then return no rows.
6484 ** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
6485 pCur->ss.iBase = 1;
6486 pCur->ss.iTerm = 0;
6487 pCur->ss.iStep = 1;
6488 break;
6489 }
6490 }
 
 
 
 
 
6491 if( idxNum & 0x08 ){
6492 pCur->ss.isReversing = pCur->ss.iStep > 0;
6493 }else{
6494 pCur->ss.isReversing = pCur->ss.iStep < 0;
6495 }
@@ -6506,17 +6940,39 @@
6506 ** In this implementation idxNum is used to represent the
6507 ** query plan. idxStr is unused.
6508 **
6509 ** The query plan is represented by bits in idxNum:
6510 **
6511 ** 0x01 start = $value -- constraint exists
6512 ** 0x02 stop = $value -- constraint exists
6513 ** 0x04 step = $value -- constraint exists
6514 ** 0x08 output is in descending order
6515 ** 0x10 output is in ascending order
6516 ** 0x20 LIMIT $value -- constraint exists
6517 ** 0x40 OFFSET $value -- constraint exists
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6518 */
6519 static int seriesBestIndex(
6520 sqlite3_vtab *pVTab,
6521 sqlite3_index_info *pIdxInfo
6522 ){
@@ -6525,19 +6981,21 @@
6525 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6526 int bStartSeen = 0; /* EQ constraint seen on the START column */
6527 #endif
6528 int unusableMask = 0; /* Mask of unusable constraints */
6529 int nArg = 0; /* Number of arguments that seriesFilter() expects */
6530 int aIdx[5]; /* Constraints on start, stop, step, LIMIT, OFFSET */
 
 
6531 const struct sqlite3_index_constraint *pConstraint;
6532
6533 /* This implementation assumes that the start, stop, and step columns
6534 ** are the last three columns in the virtual table. */
6535 assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
6536 assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
6537
6538 aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = -1;
6539 pConstraint = pIdxInfo->aConstraint;
6540 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
6541 int iCol; /* 0 for start, 1 for stop, 2 for step */
6542 int iMask; /* bitmask for those column */
6543 int op = pConstraint->op;
@@ -6554,11 +7012,54 @@
6554 aIdx[4] = i;
6555 idxNum |= 0x40;
6556 }
6557 continue;
6558 }
6559 if( pConstraint->iColumn<SERIES_COLUMN_START ) continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6560 iCol = pConstraint->iColumn - SERIES_COLUMN_START;
6561 assert( iCol>=0 && iCol<=2 );
6562 iMask = 1 << iCol;
6563 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6564 if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){
@@ -6576,11 +7077,11 @@
6576 if( aIdx[3]==0 ){
6577 /* Ignore OFFSET if LIMIT is omitted */
6578 idxNum &= ~0x60;
6579 aIdx[4] = 0;
6580 }
6581 for(i=0; i<5; i++){
6582 if( (j = aIdx[i])>=0 ){
6583 pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
6584 pIdxInfo->aConstraintUsage[j].omit =
6585 !SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3;
6586 }
@@ -6624,10 +7125,13 @@
6624 ** of numbers. Make this case very expensive so that the query
6625 ** planner will work hard to avoid it. */
6626 pIdxInfo->estimatedRows = 2147483647;
6627 }
6628 pIdxInfo->idxNum = idxNum;
 
 
 
6629 return SQLITE_OK;
6630 }
6631
6632 /*
6633 ** This following structure defines all the methods for the
@@ -22175,14 +22679,15 @@
22175 sqlite3_bind_double(pStmt, i, INFINITY);
22176 #endif
22177 }else if( strncmp(zVar, "$int_", 5)==0 ){
22178 sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
22179 }else if( strncmp(zVar, "$text_", 6)==0 ){
22180 char *zBuf = sqlite3_malloc64( strlen(zVar)-5 );
 
22181 if( zBuf ){
22182 memcpy(zBuf, &zVar[6], strlen(zVar)-5);
22183 sqlite3_bind_text64(pStmt, i, zBuf, -1, sqlite3_free, SQLITE_UTF8);
22184 }
22185 }else{
22186 sqlite3_bind_null(pStmt, i);
22187 }
22188 sqlite3_reset(pQ);
@@ -24970,16 +25475,21 @@
24970 oputf("%-20s %u\n", "data version", iDataVersion);
24971 return 0;
24972 }
24973 #endif /* SQLITE_SHELL_HAVE_RECOVER */
24974
 
 
 
 
 
 
24975 /*
24976 ** Print the current sqlite3_errmsg() value to stderr and return 1.
24977 */
24978 static int shellDatabaseError(sqlite3 *db){
24979 const char *zErr = sqlite3_errmsg(db);
24980 eputf("Error: %s\n", zErr);
24981 return 1;
24982 }
24983
24984 /*
24985 ** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
@@ -25520,11 +26030,11 @@
25520 va_list ap;
25521 char *z;
25522 va_start(ap, zFmt);
25523 z = sqlite3_vmprintf(zFmt, ap);
25524 va_end(ap);
25525 eputf("Error: %s\n", z);
25526 if( pAr->fromCmdLine ){
25527 eputz("Use \"-A\" for more help\n");
25528 }else{
25529 eputz("Use \".archive --help\" for more help\n");
25530 }
@@ -26751,20 +27261,20 @@
26751 0, 0, 0);
26752 }
26753 open_db(p, 0);
26754 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
26755 if( pBackup==0 ){
26756 eputf("Error: %s\n", sqlite3_errmsg(pDest));
26757 close_db(pDest);
26758 return 1;
26759 }
26760 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
26761 sqlite3_backup_finish(pBackup);
26762 if( rc==SQLITE_DONE ){
26763 rc = 0;
26764 }else{
26765 eputf("Error: %s\n", sqlite3_errmsg(pDest));
26766 rc = 1;
26767 }
26768 close_db(pDest);
26769 }else
26770 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -26936,11 +27446,11 @@
26936 sqlite3_stmt *pStmt;
26937 int i;
26938 open_db(p, 0);
26939 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
26940 if( rc ){
26941 eputf("Error: %s\n", sqlite3_errmsg(p->db));
26942 rc = 1;
26943 }else{
26944 while( sqlite3_step(pStmt)==SQLITE_ROW ){
26945 const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
26946 const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
@@ -27632,11 +28142,11 @@
27632 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27633 sqlite3_free(zSql);
27634 zSql = 0;
27635 if( rc ){
27636 if (pStmt) sqlite3_finalize(pStmt);
27637 eputf("Error: %s\n", sqlite3_errmsg(p->db));
27638 import_cleanup(&sCtx);
27639 rc = 1;
27640 goto meta_command_exit;
27641 }
27642 if( sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -27676,11 +28186,11 @@
27676 }
27677 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
27678 sqlite3_free(zSql);
27679 zSql = 0;
27680 if( rc ){
27681 eputf("Error: %s\n", sqlite3_errmsg(p->db));
27682 if (pStmt) sqlite3_finalize(pStmt);
27683 import_cleanup(&sCtx);
27684 rc = 1;
27685 goto meta_command_exit;
27686 }
@@ -27970,11 +28480,11 @@
27970 zFile = azArg[1];
27971 zProc = nArg>=3 ? azArg[2] : 0;
27972 open_db(p, 0);
27973 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
27974 if( rc!=SQLITE_OK ){
27975 eputf("Error: %s\n", zErrMsg);
27976 sqlite3_free(zErrMsg);
27977 rc = 1;
27978 }
27979 }else
27980 #endif
@@ -28592,11 +29102,11 @@
28592 return 1;
28593 }
28594 open_db(p, 0);
28595 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
28596 if( pBackup==0 ){
28597 eputf("Error: %s\n", sqlite3_errmsg(p->db));
28598 close_db(pSrc);
28599 return 1;
28600 }
28601 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
28602 || rc==SQLITE_BUSY ){
@@ -28610,11 +29120,11 @@
28610 rc = 0;
28611 }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
28612 eputz("Error: source database is busy\n");
28613 rc = 1;
28614 }else{
28615 eputf("Error: %s\n", sqlite3_errmsg(p->db));
28616 rc = 1;
28617 }
28618 close_db(pSrc);
28619 }else
28620 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -28707,11 +29217,11 @@
28707 if( zDiv ){
28708 sqlite3_stmt *pStmt = 0;
28709 rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
28710 -1, &pStmt, 0);
28711 if( rc ){
28712 eputf("Error: %s\n", sqlite3_errmsg(p->db));
28713 sqlite3_finalize(pStmt);
28714 rc = 1;
28715 goto meta_command_exit;
28716 }
28717 appendText(&sSelect, "SELECT sql FROM", 0);
@@ -28776,11 +29286,11 @@
28776 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
28777 }
28778 freeText(&sSelect);
28779 }
28780 if( zErrMsg ){
28781 eputf("Error: %s\n", zErrMsg);
28782 sqlite3_free(zErrMsg);
28783 rc = 1;
28784 }else if( rc != SQLITE_OK ){
28785 eputz("Error: querying schema information\n");
28786 rc = 1;
@@ -29547,11 +30057,11 @@
29547 {"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
29548 {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
29549 {"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
29550 {"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
29551 {"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
29552 {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" },
29553 #ifdef YYCOVERAGE
29554 {"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
29555 #endif
29556 {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,1, "OFFSET " },
29557 {"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
@@ -29610,13 +30120,123 @@
29610 if( testctrl<0 ){
29611 eputf("Error: unknown test-control: %s\n"
29612 "Use \".testctrl --help\" for help\n", zCmd);
29613 }else{
29614 switch(testctrl){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29615
29616 /* sqlite3_test_control(int, db, int) */
29617 case SQLITE_TESTCTRL_OPTIMIZATIONS:
29618 case SQLITE_TESTCTRL_FK_NO_ACTION:
29619 if( nArg==3 ){
29620 unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
29621 rc2 = sqlite3_test_control(testctrl, p->db, opt);
29622 isOk = 3;
@@ -31355,11 +31975,11 @@
31355 if( rc && bail_on_error ) return rc==2 ? 0 : rc;
31356 }else{
31357 open_db(&data, 0);
31358 rc = shell_exec(&data, z, &zErrMsg);
31359 if( zErrMsg!=0 ){
31360 eputf("Error: %s\n", zErrMsg);
31361 if( bail_on_error ) return rc!=0 ? rc : 1;
31362 }else if( rc!=0 ){
31363 eputf("Error: unable to process SQL \"%s\"\n", z);
31364 if( bail_on_error ) return rc;
31365 }
@@ -31409,11 +32029,11 @@
31409 open_db(&data, 0);
31410 echo_group_input(&data, azCmd[i]);
31411 rc = shell_exec(&data, azCmd[i], &zErrMsg);
31412 if( zErrMsg || rc ){
31413 if( zErrMsg!=0 ){
31414 eputf("Error: %s\n", zErrMsg);
31415 }else{
31416 eputf("Error: unable to process SQL: %s\n", azCmd[i]);
31417 }
31418 sqlite3_free(zErrMsg);
31419 if( rc==0 ) rc = 1;
31420
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -262,10 +262,11 @@
262 /* Deselect most features from the console I/O package for Fiddle. */
263 # define SQLITE_CIO_NO_REDIRECT
264 # define SQLITE_CIO_NO_CLASSIFY
265 # define SQLITE_CIO_NO_TRANSLATE
266 # define SQLITE_CIO_NO_SETMODE
267 # define SQLITE_CIO_NO_FLUSH
268 #endif
269 /************************* Begin ../ext/consio/console_io.h ******************/
270 /*
271 ** 2023 November 1
272 **
@@ -442,16 +443,23 @@
443 #ifdef CONSIO_EPUTB
444 SQLITE_INTERNAL_LINKAGE int
445 ePutbUtf8(const char *cBuf, int nAccept);
446 #endif
447
448 /*
449 ** Flush the given output stream. Return non-zero for success, else 0.
450 */
451 #if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
452 SQLITE_INTERNAL_LINKAGE int
453 fFlushBuffer(FILE *pfOut);
454 #endif
455
456 /*
457 ** Collect input like fgets(...) with special provisions for input
458 ** from the console on such platforms as require same. Newline
459 ** translation may be done as set by set{Binary,Text}Mode().
460 ** As a convenience, pfIn==NULL is treated as stdin.
 
461 */
462 SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
463 /* Like fGetsUtf8 except stream is always the designated input. */
464 /* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
465
@@ -1144,10 +1152,90 @@
1152 # if CIO_WIN_WC_XLATE
1153 }
1154 # endif
1155 }
1156
1157 /*
1158 ** Flush the given output stream. Return non-zero for success, else 0.
1159 */
1160 #if !defined(SQLITE_CIO_NO_FLUSH) && !defined(SQLITE_CIO_NO_SETMODE)
1161 SQLITE_INTERNAL_LINKAGE int
1162 fFlushBuffer(FILE *pfOut){
1163 # if CIO_WIN_WC_XLATE && !defined(SHELL_OMIT_FIO_DUPE)
1164 return FlushFileBuffers(handleOfFile(pfOut))? 1 : 0;
1165 # else
1166 return fflush(pfOut);
1167 # endif
1168 }
1169 #endif
1170
1171 #if CIO_WIN_WC_XLATE \
1172 && !defined(SHELL_OMIT_FIO_DUPE) \
1173 && defined(SQLITE_USE_ONLY_WIN32)
1174 static struct FileAltIds {
1175 int fd;
1176 HANDLE fh;
1177 } altIdsOfFile(FILE *pf){
1178 struct FileAltIds rv = { _fileno(pf) };
1179 union { intptr_t osfh; HANDLE fh; } fid = {
1180 (rv.fd>=0)? _get_osfhandle(rv.fd) : (intptr_t)INVALID_HANDLE_VALUE
1181 };
1182 rv.fh = fid.fh;
1183 return rv;
1184 }
1185
1186 SQLITE_INTERNAL_LINKAGE size_t
1187 cfWrite(const void *buf, size_t osz, size_t ocnt, FILE *pf){
1188 size_t rv = 0;
1189 struct FileAltIds fai = altIdsOfFile(pf);
1190 int fmode = _setmode(fai.fd, _O_BINARY);
1191 _setmode(fai.fd, fmode);
1192 while( rv < ocnt ){
1193 size_t nbo = osz;
1194 while( nbo > 0 ){
1195 DWORD dwno = (nbo>(1L<<24))? 1L<<24 : (DWORD)nbo;
1196 BOOL wrc = TRUE;
1197 BOOL genCR = (fmode & _O_TEXT)!=0;
1198 if( genCR ){
1199 const char *pnl = (const char*)memchr(buf, '\n', nbo);
1200 if( pnl ) nbo = pnl - (const char*)buf;
1201 else genCR = 0;
1202 }
1203 if( dwno>0 ) wrc = WriteFile(fai.fh, buf, dwno, 0,0);
1204 if( genCR && wrc ){
1205 wrc = WriteFile(fai.fh, "\r\n", 2, 0,0);
1206 ++dwno; /* Skip over the LF */
1207 }
1208 if( !wrc ) return rv;
1209 buf = (const char*)buf + dwno;
1210 nbo += dwno;
1211 }
1212 ++rv;
1213 }
1214 return rv;
1215 }
1216
1217 SQLITE_INTERNAL_LINKAGE char *
1218 cfGets(char *cBuf, int n, FILE *pf){
1219 int nci = 0;
1220 struct FileAltIds fai = altIdsOfFile(pf);
1221 int fmode = _setmode(fai.fd, _O_BINARY);
1222 BOOL eatCR = (fmode & _O_TEXT)!=0;
1223 _setmode(fai.fd, fmode);
1224 while( nci < n-1 ){
1225 DWORD nr;
1226 if( !ReadFile(fai.fh, cBuf+nci, 1, &nr, 0) || nr==0 ) break;
1227 if( nr>0 && (!eatCR || cBuf[nci]!='\r') ) nci += nr;
1228 }
1229 if( nci < n ) cBuf[nci] = 0;
1230 return (nci>0)? cBuf : 0;
1231 }
1232 # else
1233 # define cfWrite(b,os,no,f) fwrite(b,os,no,f)
1234 # define cfGets(b,n,f) fgets(b,n,f)
1235 # endif
1236
1237 # ifdef CONSIO_EPUTB
1238 SQLITE_INTERNAL_LINKAGE int
1239 ePutbUtf8(const char *cBuf, int nAccept){
1240 FILE *pfErr;
1241 PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
@@ -1155,11 +1243,11 @@
1243 # if CIO_WIN_WC_XLATE
1244 if( pstReachesConsole(ppst) ){
1245 return conZstrEmit(ppst, cBuf, nAccept);
1246 }else {
1247 # endif
1248 return (int)cfWrite(cBuf, 1, nAccept, pfErr);
1249 # if CIO_WIN_WC_XLATE
1250 }
1251 # endif
1252 }
1253 # endif /* defined(CONSIO_EPUTB) */
@@ -1221,11 +1309,11 @@
1309 return cBuf;
1310 }else return 0;
1311 # endif
1312 }else{
1313 # endif
1314 return cfGets(cBuf, ncMax, pfIn);
1315 # if CIO_WIN_WC_XLATE
1316 }
1317 # endif
1318 }
1319 #endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
@@ -1265,15 +1353,16 @@
1353 # define oputz(z) oPutsUtf8(z)
1354 # define oputf oPrintfUtf8
1355 # define eputz(z) ePutsUtf8(z)
1356 # define eputf ePrintfUtf8
1357 # define oputb(buf,na) oPutbUtf8(buf,na)
1358 # define fflush(s) fFlushBuffer(s);
1359
1360 #else
1361 /* For Fiddle, all console handling and emit redirection is omitted. */
1362 /* These next 3 macros are for emitting formatted output. When complaints
1363 * from the WASM build are issued for non-formatted output, when a mere
1364 * string literal is to be emitted, the ?putz(z) forms should be used.
1365 * (This permits compile-time checking of format string / argument mismatch.)
1366 */
1367 # define oputf(fmt, ...) printf(fmt,__VA_ARGS__)
1368 # define eputf(fmt, ...) fprintf(stderr,fmt,__VA_ARGS__)
@@ -1281,10 +1370,11 @@
1370 /* These next 3 macros are for emitting simple string literals. */
1371 # define oputz(z) fputs(z,stdout)
1372 # define eputz(z) fputs(z,stderr)
1373 # define sputz(fp,z) fputs(z,fp)
1374 # define oputb(buf,na) fwrite(buf,1,na,stdout)
1375 # undef fflush
1376 #endif
1377
1378 /* True if the timer is enabled */
1379 static int enableTimer = 0;
1380
@@ -1519,10 +1609,18 @@
1609 size_t i;
1610 for(i=0; i<n-1 && src[i]!=0; i++) dest[i] = src[i];
1611 dest[i] = 0;
1612 return dest;
1613 }
1614
1615 /*
1616 ** strcpy() workalike to squelch an unwarranted link-time warning
1617 ** from OpenBSD.
1618 */
1619 static void shell_strcpy(char *dest, const char *src){
1620 while( (*(dest++) = *(src++))!=0 ){}
1621 }
1622
1623 /*
1624 ** Optionally disable dynamic continuation prompt.
1625 ** Unless disabled, the continuation prompt shows open SQL lexemes if any,
1626 ** or open parentheses level if non-zero, or continuation prompt as set.
@@ -1585,11 +1683,11 @@
1683 }else{
1684 if( dynPrompt.zScannerAwaits ){
1685 size_t ncp = strlen(continuePrompt);
1686 size_t ndp = strlen(dynPrompt.zScannerAwaits);
1687 if( ndp > ncp-3 ) return continuePrompt;
1688 shell_strcpy(dynPrompt.dynamicPrompt, dynPrompt.zScannerAwaits);
1689 while( ndp<3 ) dynPrompt.dynamicPrompt[ndp++] = ' ';
1690 shell_strncpy(dynPrompt.dynamicPrompt+3, continuePrompt+3,
1691 PROMPT_LEN_MAX-4);
1692 }else{
1693 if( dynPrompt.inParenLevel>9 ){
@@ -4681,11 +4779,11 @@
4779 ** May you share freely, never taking more than you give.
4780 **
4781 ******************************************************************************
4782 **
4783 ** This file contains code to implement the percentile(Y,P) SQL function
4784 ** and similar as described below:
4785 **
4786 ** (1) The percentile(Y,P) function is an aggregate function taking
4787 ** exactly two arguments.
4788 **
4789 ** (2) If the P argument to percentile(Y,P) is not the same for every
@@ -4730,48 +4828,173 @@
4828 ** file that compiles into a shared-library or DLL that can be loaded
4829 ** into SQLite using the sqlite3_load_extension() interface.
4830 **
4831 ** (13) A separate median(Y) function is the equivalent percentile(Y,50).
4832 **
4833 ** (14) A separate percentile_cont(Y,P) function is equivalent to
4834 ** percentile(Y,P/100.0). In other words, the fraction value in
4835 ** the second argument is in the range of 0 to 1 instead of 0 to 100.
4836 **
4837 ** (15) A separate percentile_disc(Y,P) function is like
4838 ** percentile_cont(Y,P) except that instead of returning the weighted
4839 ** average of the nearest two input values, it returns the next lower
4840 ** value. So the percentile_disc(Y,P) will always return a value
4841 ** that was one of the inputs.
4842 **
4843 ** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and
4844 ** percentile_disc(Y,P) can be used as window functions.
4845 **
4846 ** Differences from standard SQL:
4847 **
4848 ** * The percentile_cont(X,P) function is equivalent to the following in
4849 ** standard SQL:
4850 **
4851 ** (percentile_cont(P) WITHIN GROUP (ORDER BY X))
4852 **
4853 ** The SQLite syntax is much more compact. The standard SQL syntax
4854 ** is also supported if SQLite is compiled with the
4855 ** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option.
4856 **
4857 ** * No median(X) function exists in the SQL standard. App developers
4858 ** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)".
4859 **
4860 ** * No percentile(Y,P) function exists in the SQL standard. Instead of
4861 ** percential(Y,P), developers must write this:
4862 ** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that
4863 ** the fraction parameter to percentile() goes from 0 to 100 whereas
4864 ** the fraction parameter in SQL standard percentile_cont() goes from
4865 ** 0 to 1.
4866 **
4867 ** Implementation notes as of 2024-08-31:
4868 **
4869 ** * The regular aggregate-function versions of these routines work
4870 ** by accumulating all values in an array of doubles, then sorting
4871 ** that array using quicksort before computing the answer. Thus
4872 ** the runtime is O(NlogN) where N is the number of rows of input.
4873 **
4874 ** * For the window-function versions of these routines, the array of
4875 ** inputs is sorted as soon as the first value is computed. Thereafter,
4876 ** the array is kept in sorted order using an insert-sort. This
4877 ** results in O(N*K) performance where K is the size of the window.
4878 ** One can imagine alternative implementations that give O(N*logN*logK)
4879 ** performance, but they require more complex logic and data structures.
4880 ** The developers have elected to keep the asymptotically slower
4881 ** algorithm for now, for simplicity, under the theory that window
4882 ** functions are seldom used and when they are, the window size K is
4883 ** often small. The developers might revisit that decision later,
4884 ** should the need arise.
4885 */
4886 #if defined(SQLITE3_H)
4887 /* no-op */
4888 #elif defined(SQLITE_STATIC_PERCENTILE)
4889 /* # include "sqlite3.h" */
4890 #else
4891 /* # include "sqlite3ext.h" */
4892 SQLITE_EXTENSION_INIT1
4893 #endif
4894 #include <assert.h>
4895 #include <string.h>
4896 #include <stdlib.h>
4897
4898 /* The following object is the group context for a single percentile()
4899 ** aggregate. Remember all input Y values until the very end.
4900 ** Those values are accumulated in the Percentile.a[] array.
4901 */
4902 typedef struct Percentile Percentile;
4903 struct Percentile {
4904 unsigned nAlloc; /* Number of slots allocated for a[] */
4905 unsigned nUsed; /* Number of slots actually used in a[] */
4906 char bSorted; /* True if a[] is already in sorted order */
4907 char bKeepSorted; /* True if advantageous to keep a[] sorted */
4908 char bPctValid; /* True if rPct is valid */
4909 double rPct; /* Fraction. 0.0 to 1.0 */
4910 double *a; /* Array of Y values */
4911 };
4912
4913 /* Details of each function in the percentile family */
4914 typedef struct PercentileFunc PercentileFunc;
4915 struct PercentileFunc {
4916 const char *zName; /* Function name */
4917 char nArg; /* Number of arguments */
4918 char mxFrac; /* Maximum value of the "fraction" input */
4919 char bDiscrete; /* True for percentile_disc() */
4920 };
4921 static const PercentileFunc aPercentFunc[] = {
4922 { "median", 1, 1, 0 },
4923 { "percentile", 2, 100, 0 },
4924 { "percentile_cont", 2, 1, 0 },
4925 { "percentile_disc", 2, 1, 1 },
4926 };
4927
4928 /*
4929 ** Return TRUE if the input floating-point number is an infinity.
4930 */
4931 static int percentIsInfinity(double r){
4932 sqlite3_uint64 u;
4933 assert( sizeof(u)==sizeof(r) );
4934 memcpy(&u, &r, sizeof(u));
4935 return ((u>>52)&0x7ff)==0x7ff;
4936 }
4937
4938 /*
4939 ** Return TRUE if two doubles differ by 0.001 or less.
4940 */
4941 static int percentSameValue(double a, double b){
4942 a -= b;
4943 return a>=-0.001 && a<=0.001;
4944 }
4945
4946 /*
4947 ** Search p (which must have p->bSorted) looking for an entry with
4948 ** value y. Return the index of that entry.
4949 **
4950 ** If bExact is true, return -1 if the entry is not found.
4951 **
4952 ** If bExact is false, return the index at which a new entry with
4953 ** value y should be insert in order to keep the values in sorted
4954 ** order. The smallest return value in this case will be 0, and
4955 ** the largest return value will be p->nUsed.
4956 */
4957 static int percentBinarySearch(Percentile *p, double y, int bExact){
4958 int iFirst = 0; /* First element of search range */
4959 int iLast = p->nUsed - 1; /* Last element of search range */
4960 while( iLast>=iFirst ){
4961 int iMid = (iFirst+iLast)/2;
4962 double x = p->a[iMid];
4963 if( x<y ){
4964 iFirst = iMid + 1;
4965 }else if( x>y ){
4966 iLast = iMid - 1;
4967 }else{
4968 return iMid;
4969 }
4970 }
4971 if( bExact ) return -1;
4972 return iFirst;
4973 }
4974
4975 /*
4976 ** Generate an error for a percentile function.
4977 **
4978 ** The error format string must have exactly one occurrance of "%%s()"
4979 ** (with two '%' characters). That substring will be replaced by the name
4980 ** of the function.
4981 */
4982 static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){
4983 PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
4984 char *zMsg1;
4985 char *zMsg2;
4986 va_list ap;
4987
4988 va_start(ap, zFormat);
4989 zMsg1 = sqlite3_vmprintf(zFormat, ap);
4990 va_end(ap);
4991 zMsg2 = zMsg1 ? sqlite3_mprintf(zMsg1, pFunc->zName) : 0;
4992 sqlite3_result_error(pCtx, zMsg2, -1);
4993 sqlite3_free(zMsg1);
4994 sqlite3_free(zMsg2);
4995 }
4996
4997 /*
4998 ** The "step" function for percentile(Y,P) is called once for each
4999 ** input row.
5000 */
@@ -4782,45 +5005,38 @@
5005 double y;
5006 assert( argc==2 || argc==1 );
5007
5008 if( argc==1 ){
5009 /* Requirement 13: median(Y) is the same as percentile(Y,50). */
5010 rPct = 0.5;
5011 }else{
5012 /* Requirement 3: P must be a number between 0 and 100 */
5013 PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
5014 eType = sqlite3_value_numeric_type(argv[1]);
5015 rPct = sqlite3_value_double(argv[1])/(double)pFunc->mxFrac;
5016 if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT)
5017 || rPct<0.0 || rPct>1.0
5018 ){
5019 percentError(pCtx, "the fraction argument to %%s()"
5020 " is not between 0.0 and %.1f",
5021 (double)pFunc->mxFrac);
5022 return;
5023 }
 
 
 
 
 
 
 
 
5024 }
5025
5026 /* Allocate the session context. */
5027 p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
5028 if( p==0 ) return;
5029
5030 /* Remember the P value. Throw an error if the P value is different
5031 ** from any prior row, per Requirement (2). */
5032 if( !p->bPctValid ){
5033 p->rPct = rPct;
5034 p->bPctValid = 1;
5035 }else if( !percentSameValue(p->rPct,rPct) ){
5036 percentError(pCtx, "the fraction argument to %%s()"
5037 " is not the same for all input rows");
5038 return;
5039 }
5040
5041 /* Ignore rows for which Y is NULL */
5042 eType = sqlite3_value_type(argv[0]);
@@ -4827,19 +5043,18 @@
5043 if( eType==SQLITE_NULL ) return;
5044
5045 /* If not NULL, then Y must be numeric. Otherwise throw an error.
5046 ** Requirement 4 */
5047 if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
5048 percentError(pCtx, "input to %%s() is not numeric");
 
5049 return;
5050 }
5051
5052 /* Throw an error if the Y value is infinity or NaN */
5053 y = sqlite3_value_double(argv[0]);
5054 if( percentIsInfinity(y) ){
5055 percentError(pCtx, "Inf input to %%s()");
5056 return;
5057 }
5058
5059 /* Allocate and store the Y */
5060 if( p->nUsed>=p->nAlloc ){
@@ -4852,112 +5067,209 @@
5067 return;
5068 }
5069 p->nAlloc = n;
5070 p->a = a;
5071 }
5072 if( p->nUsed==0 ){
5073 p->a[p->nUsed++] = y;
5074 p->bSorted = 1;
5075 }else if( !p->bSorted || y>=p->a[p->nUsed-1] ){
5076 p->a[p->nUsed++] = y;
5077 }else if( p->bKeepSorted ){
5078 int i;
5079 i = percentBinarySearch(p, y, 0);
5080 if( i<p->nUsed ){
5081 memmove(&p->a[i+1], &p->a[i], (p->nUsed-i)*sizeof(p->a[0]));
5082 }
5083 p->a[i] = y;
5084 p->nUsed++;
5085 }else{
5086 p->a[p->nUsed++] = y;
5087 p->bSorted = 0;
5088 }
5089 }
5090
5091 /*
5092 ** Interchange two doubles.
5093 */
5094 #define SWAP_DOUBLE(X,Y) {double ttt=(X);(X)=(Y);(Y)=ttt;}
5095
5096 /*
5097 ** Sort an array of doubles.
5098 **
5099 ** Algorithm: quicksort
5100 **
5101 ** This is implemented separately rather than using the qsort() routine
5102 ** from the standard library because:
5103 **
5104 ** (1) To avoid a dependency on qsort()
5105 ** (2) To avoid the function call to the comparison routine for each
5106 ** comparison.
5107 */
5108 static void percentSort(double *a, unsigned int n){
5109 int iLt; /* Entries before a[iLt] are less than rPivot */
5110 int iGt; /* Entries at or after a[iGt] are greater than rPivot */
5111 int i; /* Loop counter */
5112 double rPivot; /* The pivot value */
5113
5114 assert( n>=2 );
5115 if( a[0]>a[n-1] ){
5116 SWAP_DOUBLE(a[0],a[n-1])
5117 }
5118 if( n==2 ) return;
5119 iGt = n-1;
5120 i = n/2;
5121 if( a[0]>a[i] ){
5122 SWAP_DOUBLE(a[0],a[i])
5123 }else if( a[i]>a[iGt] ){
5124 SWAP_DOUBLE(a[i],a[iGt])
5125 }
5126 if( n==3 ) return;
5127 rPivot = a[i];
5128 iLt = i = 1;
5129 do{
5130 if( a[i]<rPivot ){
5131 if( i>iLt ) SWAP_DOUBLE(a[i],a[iLt])
 
 
 
 
5132 iLt++;
5133 i++;
5134 }else if( a[i]>rPivot ){
5135 do{
5136 iGt--;
5137 }while( iGt>i && a[iGt]>rPivot );
5138 SWAP_DOUBLE(a[i],a[iGt])
 
 
5139 }else{
5140 i++;
5141 }
5142 }while( i<iGt );
5143 if( iLt>=2 ) percentSort(a, iLt);
5144 if( n-iGt>=2 ) percentSort(a+iGt, n-iGt);
5145
5146 /* Uncomment for testing */
5147 #if 0
5148 for(i=0; i<n-1; i++){
5149 assert( a[i]<=a[i+1] );
5150 }
5151 #endif
5152 }
5153
5154
5155 /*
5156 ** The "inverse" function for percentile(Y,P) is called to remove a
5157 ** row that was previously inserted by "step".
5158 */
5159 static void percentInverse(sqlite3_context *pCtx,int argc,sqlite3_value **argv){
5160 Percentile *p;
5161 int eType;
5162 double y;
5163 int i;
5164 assert( argc==2 || argc==1 );
5165
5166 /* Allocate the session context. */
5167 p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p));
5168 assert( p!=0 );
5169
5170 /* Ignore rows for which Y is NULL */
5171 eType = sqlite3_value_type(argv[0]);
5172 if( eType==SQLITE_NULL ) return;
5173
5174 /* If not NULL, then Y must be numeric. Otherwise throw an error.
5175 ** Requirement 4 */
5176 if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){
5177 return;
5178 }
5179
5180 /* Ignore the Y value if it is infinity or NaN */
5181 y = sqlite3_value_double(argv[0]);
5182 if( percentIsInfinity(y) ){
5183 return;
5184 }
5185 if( p->bSorted==0 ){
5186 assert( p->nUsed>1 );
5187 percentSort(p->a, p->nUsed);
5188 p->bSorted = 1;
5189 }
5190 p->bKeepSorted = 1;
5191
5192 /* Find and remove the row */
5193 i = percentBinarySearch(p, y, 1);
5194 if( i>=0 ){
5195 p->nUsed--;
5196 if( i<p->nUsed ){
5197 memmove(&p->a[i], &p->a[i+1], (p->nUsed - i)*sizeof(p->a[0]));
5198 }
5199 }
5200 }
5201
5202 /*
5203 ** Compute the final output of percentile(). Clean up all allocated
5204 ** memory if and only if bIsFinal is true.
5205 */
5206 static void percentCompute(sqlite3_context *pCtx, int bIsFinal){
5207 Percentile *p;
5208 PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
5209 unsigned i1, i2;
5210 double v1, v2;
5211 double ix, vx;
5212 p = (Percentile*)sqlite3_aggregate_context(pCtx, 0);
5213 if( p==0 ) return;
5214 if( p->a==0 ) return;
5215 if( p->nUsed ){
5216 if( p->bSorted==0 ){
5217 assert( p->nUsed>1 );
5218 percentSort(p->a, p->nUsed);
5219 p->bSorted = 1;
5220 }
5221 ix = p->rPct*(p->nUsed-1);
5222 i1 = (unsigned)ix;
5223 if( pFunc->bDiscrete ){
5224 vx = p->a[i1];
5225 }else{
5226 i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1;
5227 v1 = p->a[i1];
5228 v2 = p->a[i2];
5229 vx = v1 + (v2-v1)*(ix-i1);
5230 }
5231 sqlite3_result_double(pCtx, vx);
5232 }
5233 if( bIsFinal ){
5234 sqlite3_free(p->a);
5235 memset(p, 0, sizeof(*p));
5236 }else{
5237 p->bKeepSorted = 1;
5238 }
5239 }
5240 static void percentFinal(sqlite3_context *pCtx){
5241 percentCompute(pCtx, 1);
5242 }
5243 static void percentValue(sqlite3_context *pCtx){
5244 percentCompute(pCtx, 0);
5245 }
5246
5247 #if defined(_WIN32) && !defined(SQLITE3_H) && !defined(SQLITE_STATIC_PERCENTILE)
 
5248
5249 #endif
5250 int sqlite3_percentile_init(
5251 sqlite3 *db,
5252 char **pzErrMsg,
5253 const sqlite3_api_routines *pApi
5254 ){
5255 int rc = SQLITE_OK;
5256 int i;
5257 #if defined(SQLITE3_H) || defined(SQLITE_STATIC_PERCENTILE)
5258 (void)pApi; /* Unused parameter */
5259 #else
5260 SQLITE_EXTENSION_INIT2(pApi);
5261 #endif
5262 (void)pzErrMsg; /* Unused parameter */
5263 for(i=0; i<sizeof(aPercentFunc)/sizeof(aPercentFunc[0]); i++){
5264 rc = sqlite3_create_window_function(db,
5265 aPercentFunc[i].zName,
5266 aPercentFunc[i].nArg,
5267 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_SELFORDER1,
5268 (void*)&aPercentFunc[i],
5269 percentStep, percentFinal, percentValue, percentInverse, 0);
5270 if( rc ) break;
 
 
 
 
5271 }
5272 return rc;
5273 }
5274
5275 /************************* End ../ext/misc/percentile.c ********************/
@@ -6132,10 +6444,30 @@
6444 ** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step.
6445 ** xBestIndex returns a small cost when both start and stop are available,
6446 ** and a very large cost if either start or stop are unavailable. This
6447 ** encourages the query planner to order joins such that the bounds of the
6448 ** series are well-defined.
6449 **
6450 ** Update on 2024-08-22:
6451 ** xBestIndex now also looks for equality and inequality constraints against
6452 ** the value column and uses those constraints as additional bounds against
6453 ** the sequence range. Thus, a query like this:
6454 **
6455 ** SELECT value FROM generate_series($SA,$EA)
6456 ** WHERE value BETWEEN $SB AND $EB;
6457 **
6458 ** Is logically the same as:
6459 **
6460 ** SELECT value FROM generate_series(max($SA,$SB),min($EA,$EB));
6461 **
6462 ** Constraints on the value column can server as substitutes for constraints
6463 ** on the hidden start and stop columns. So, the following two queries
6464 ** are equivalent:
6465 **
6466 ** SELECT value FROM generate_series($S,$E);
6467 ** SELECT value FROM generate_series WHERE value BETWEEN $S and $E;
6468 **
6469 */
6470 /* #include "sqlite3ext.h" */
6471 SQLITE_EXTENSION_INIT1
6472 #include <assert.h>
6473 #include <string.h>
@@ -6173,12 +6505,14 @@
6505 }
6506
6507 /* typedef unsigned char u8; */
6508
6509 typedef struct SequenceSpec {
6510 sqlite3_int64 iOBase; /* Original starting value ("start") */
6511 sqlite3_int64 iOTerm; /* Original terminal value ("stop") */
6512 sqlite3_int64 iBase; /* Starting value to actually use */
6513 sqlite3_int64 iTerm; /* Terminal value to actually use */
6514 sqlite3_int64 iStep; /* Increment ("step") */
6515 sqlite3_uint64 uSeqIndexMax; /* maximum sequence index (aka "n") */
6516 sqlite3_uint64 uSeqIndexNow; /* Current index during generation */
6517 sqlite3_int64 iValueNow; /* Current value during generation */
6518 u8 isNotEOF; /* Sequence generation not exhausted */
@@ -6367,21 +6701,23 @@
6701 int i /* Which column to return */
6702 ){
6703 series_cursor *pCur = (series_cursor*)cur;
6704 sqlite3_int64 x = 0;
6705 switch( i ){
6706 case SERIES_COLUMN_START: x = pCur->ss.iOBase; break;
6707 case SERIES_COLUMN_STOP: x = pCur->ss.iOTerm; break;
6708 case SERIES_COLUMN_STEP: x = pCur->ss.iStep; break;
6709 default: x = pCur->ss.iValueNow; break;
6710 }
6711 sqlite3_result_int64(ctx, x);
6712 return SQLITE_OK;
6713 }
6714
6715 #ifndef LARGEST_UINT64
6716 #define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
6717 #define LARGEST_UINT64 (0xffffffff|(((sqlite3_uint64)0xffffffff)<<32))
6718 #define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
6719 #endif
6720
6721 /*
6722 ** Return the rowid for the current row, logically equivalent to n+1 where
6723 ** "n" is the ascending integer in the aforesaid production definition.
@@ -6418,17 +6754,22 @@
6754 **
6755 ** The query plan selected by seriesBestIndex is passed in the idxNum
6756 ** parameter. (idxStr is not used in this implementation.) idxNum
6757 ** is a bitmask showing which constraints are available:
6758 **
6759 ** 0x0001: start=VALUE
6760 ** 0x0002: stop=VALUE
6761 ** 0x0004: step=VALUE
6762 ** 0x0008: descending order
6763 ** 0x0010: ascending order
6764 ** 0x0020: LIMIT VALUE
6765 ** 0x0040: OFFSET VALUE
6766 ** 0x0080: value=VALUE
6767 ** 0x0100: value>=VALUE
6768 ** 0x0200: value>VALUE
6769 ** 0x1000: value<=VALUE
6770 ** 0x2000: value<VALUE
6771 **
6772 ** This routine should initialize the cursor and position it so that it
6773 ** is pointing at the first row, or pointing off the end of the table
6774 ** (so that seriesEof() will return true) if the table is empty.
6775 */
@@ -6437,10 +6778,16 @@
6778 int idxNum, const char *idxStrUnused,
6779 int argc, sqlite3_value **argv
6780 ){
6781 series_cursor *pCur = (series_cursor *)pVtabCursor;
6782 int i = 0;
6783 int returnNoRows = 0;
6784 sqlite3_int64 iMin = SMALLEST_INT64;
6785 sqlite3_int64 iMax = LARGEST_INT64;
6786 sqlite3_int64 iLimit = 0;
6787 sqlite3_int64 iOffset = 0;
6788
6789 (void)idxStrUnused;
6790 if( idxNum & 0x01 ){
6791 pCur->ss.iBase = sqlite3_value_int64(argv[i++]);
6792 }else{
6793 pCur->ss.iBase = 0;
@@ -6458,38 +6805,125 @@
6805 if( (idxNum & 0x10)==0 ) idxNum |= 0x08;
6806 }
6807 }else{
6808 pCur->ss.iStep = 1;
6809 }
6810
6811 /* If there are constraints on the value column but there are
6812 ** no constraints on the start, stop, and step columns, then
6813 ** initialize the default range to be the entire range of 64-bit signed
6814 ** integers. This range will contracted by the value column constraints
6815 ** further below.
6816 */
6817 if( (idxNum & 0x05)==0 && (idxNum & 0x0380)!=0 ){
6818 pCur->ss.iBase = SMALLEST_INT64;
6819 }
6820 if( (idxNum & 0x06)==0 && (idxNum & 0x3080)!=0 ){
6821 pCur->ss.iTerm = LARGEST_INT64;
6822 }
6823 pCur->ss.iOBase = pCur->ss.iBase;
6824 pCur->ss.iOTerm = pCur->ss.iTerm;
6825
6826 /* Extract the LIMIT and OFFSET values, but do not apply them yet.
6827 ** The range must first be constrained by the limits on value.
6828 */
6829 if( idxNum & 0x20 ){
6830 iLimit = sqlite3_value_int64(argv[i++]);
 
6831 if( idxNum & 0x40 ){
6832 iOffset = sqlite3_value_int64(argv[i++]);
6833 }
6834 }
6835
6836 if( idxNum & 0x3380 ){
6837 /* Extract the maximum range of output values determined by
6838 ** constraints on the "value" column.
6839 */
6840 if( idxNum & 0x0080 ){
6841 iMin = iMax = sqlite3_value_int64(argv[i++]);
6842 }else{
6843 if( idxNum & 0x0300 ){
6844 iMin = sqlite3_value_int64(argv[i++]);
6845 if( idxNum & 0x0200 ){
6846 if( iMin==LARGEST_INT64 ){
6847 returnNoRows = 1;
6848 }else{
6849 iMin++;
6850 }
6851 }
6852 }
6853 if( idxNum & 0x3000 ){
6854 iMax = sqlite3_value_int64(argv[i++]);
6855 if( idxNum & 0x2000 ){
6856 if( iMax==SMALLEST_INT64 ){
6857 returnNoRows = 1;
6858 }else{
6859 iMax--;
6860 }
6861 }
6862 }
6863 if( iMin>iMax ){
6864 returnNoRows = 1;
6865 }
6866 }
6867
6868 /* Try to reduce the range of values to be generated based on
6869 ** constraints on the "value" column.
6870 */
6871 if( pCur->ss.iStep>0 ){
6872 sqlite3_int64 szStep = pCur->ss.iStep;
6873 if( pCur->ss.iBase<iMin ){
6874 sqlite3_uint64 d = iMin - pCur->ss.iBase;
6875 pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
6876 }
6877 if( pCur->ss.iTerm>iMax ){
6878 sqlite3_uint64 d = pCur->ss.iTerm - iMax;
6879 pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
6880 }
6881 }else{
6882 sqlite3_int64 szStep = -pCur->ss.iStep;
6883 assert( szStep>0 );
6884 if( pCur->ss.iBase>iMax ){
6885 sqlite3_uint64 d = pCur->ss.iBase - iMax;
6886 pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
6887 }
6888 if( pCur->ss.iTerm<iMin ){
6889 sqlite3_uint64 d = iMin - pCur->ss.iTerm;
6890 pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
6891 }
6892 }
6893 }
6894
6895 /* Apply LIMIT and OFFSET constraints, if any */
6896 if( idxNum & 0x20 ){
6897 if( iOffset>0 ){
6898 pCur->ss.iBase += pCur->ss.iStep*iOffset;
6899 }
6900 if( iLimit>=0 ){
6901 sqlite3_int64 iTerm;
6902 iTerm = pCur->ss.iBase + (iLimit - 1)*pCur->ss.iStep;
6903 if( pCur->ss.iStep<0 ){
6904 if( iTerm>pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
6905 }else{
6906 if( iTerm<pCur->ss.iTerm ) pCur->ss.iTerm = iTerm;
6907 }
6908 }
6909 }
6910
6911
6912 for(i=0; i<argc; i++){
6913 if( sqlite3_value_type(argv[i])==SQLITE_NULL ){
6914 /* If any of the constraints have a NULL value, then return no rows.
6915 ** See ticket https://www.sqlite.org/src/info/fac496b61722daf2 */
6916 returnNoRows = 1;
 
 
6917 break;
6918 }
6919 }
6920 if( returnNoRows ){
6921 pCur->ss.iBase = 1;
6922 pCur->ss.iTerm = 0;
6923 pCur->ss.iStep = 1;
6924 }
6925 if( idxNum & 0x08 ){
6926 pCur->ss.isReversing = pCur->ss.iStep > 0;
6927 }else{
6928 pCur->ss.isReversing = pCur->ss.iStep < 0;
6929 }
@@ -6506,17 +6940,39 @@
6940 ** In this implementation idxNum is used to represent the
6941 ** query plan. idxStr is unused.
6942 **
6943 ** The query plan is represented by bits in idxNum:
6944 **
6945 ** 0x0001 start = $num
6946 ** 0x0002 stop = $num
6947 ** 0x0004 step = $num
6948 ** 0x0008 output is in descending order
6949 ** 0x0010 output is in ascending order
6950 ** 0x0020 LIMIT $num
6951 ** 0x0040 OFFSET $num
6952 ** 0x0080 value = $num
6953 ** 0x0100 value >= $num
6954 ** 0x0200 value > $num
6955 ** 0x1000 value <= $num
6956 ** 0x2000 value < $num
6957 **
6958 ** Only one of 0x0100 or 0x0200 will be returned. Similarly, only
6959 ** one of 0x1000 or 0x2000 will be returned. If the 0x0080 is set, then
6960 ** none of the 0xff00 bits will be set.
6961 **
6962 ** The order of parameters passed to xFilter is as follows:
6963 **
6964 ** * The argument to start= if bit 0x0001 is in the idxNum mask
6965 ** * The argument to stop= if bit 0x0002 is in the idxNum mask
6966 ** * The argument to step= if bit 0x0004 is in the idxNum mask
6967 ** * The argument to LIMIT if bit 0x0020 is in the idxNum mask
6968 ** * The argument to OFFSET if bit 0x0040 is in the idxNum mask
6969 ** * The argument to value=, or value>= or value> if any of
6970 ** bits 0x0380 are in the idxNum mask
6971 ** * The argument to value<= or value< if either of bits 0x3000
6972 ** are in the mask
6973 **
6974 */
6975 static int seriesBestIndex(
6976 sqlite3_vtab *pVTab,
6977 sqlite3_index_info *pIdxInfo
6978 ){
@@ -6525,19 +6981,21 @@
6981 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
6982 int bStartSeen = 0; /* EQ constraint seen on the START column */
6983 #endif
6984 int unusableMask = 0; /* Mask of unusable constraints */
6985 int nArg = 0; /* Number of arguments that seriesFilter() expects */
6986 int aIdx[7]; /* Constraints on start, stop, step, LIMIT, OFFSET,
6987 ** and value. aIdx[5] covers value=, value>=, and
6988 ** value>, aIdx[6] covers value<= and value< */
6989 const struct sqlite3_index_constraint *pConstraint;
6990
6991 /* This implementation assumes that the start, stop, and step columns
6992 ** are the last three columns in the virtual table. */
6993 assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 );
6994 assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 );
6995
6996 aIdx[0] = aIdx[1] = aIdx[2] = aIdx[3] = aIdx[4] = aIdx[5] = aIdx[6] = -1;
6997 pConstraint = pIdxInfo->aConstraint;
6998 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
6999 int iCol; /* 0 for start, 1 for stop, 2 for step */
7000 int iMask; /* bitmask for those column */
7001 int op = pConstraint->op;
@@ -6554,11 +7012,54 @@
7012 aIdx[4] = i;
7013 idxNum |= 0x40;
7014 }
7015 continue;
7016 }
7017 if( pConstraint->iColumn==SERIES_COLUMN_VALUE ){
7018 switch( op ){
7019 case SQLITE_INDEX_CONSTRAINT_EQ:
7020 case SQLITE_INDEX_CONSTRAINT_IS: {
7021 idxNum |= 0x0080;
7022 idxNum &= ~0x3300;
7023 aIdx[5] = i;
7024 aIdx[6] = -1;
7025 bStartSeen = 1;
7026 break;
7027 }
7028 case SQLITE_INDEX_CONSTRAINT_GE: {
7029 if( idxNum & 0x0080 ) break;
7030 idxNum |= 0x0100;
7031 idxNum &= ~0x0200;
7032 aIdx[5] = i;
7033 bStartSeen = 1;
7034 break;
7035 }
7036 case SQLITE_INDEX_CONSTRAINT_GT: {
7037 if( idxNum & 0x0080 ) break;
7038 idxNum |= 0x0200;
7039 idxNum &= ~0x0100;
7040 aIdx[5] = i;
7041 bStartSeen = 1;
7042 break;
7043 }
7044 case SQLITE_INDEX_CONSTRAINT_LE: {
7045 if( idxNum & 0x0080 ) break;
7046 idxNum |= 0x1000;
7047 idxNum &= ~0x2000;
7048 aIdx[6] = i;
7049 break;
7050 }
7051 case SQLITE_INDEX_CONSTRAINT_LT: {
7052 if( idxNum & 0x0080 ) break;
7053 idxNum |= 0x2000;
7054 idxNum &= ~0x1000;
7055 aIdx[6] = i;
7056 break;
7057 }
7058 }
7059 continue;
7060 }
7061 iCol = pConstraint->iColumn - SERIES_COLUMN_START;
7062 assert( iCol>=0 && iCol<=2 );
7063 iMask = 1 << iCol;
7064 #ifndef ZERO_ARGUMENT_GENERATE_SERIES
7065 if( iCol==0 && op==SQLITE_INDEX_CONSTRAINT_EQ ){
@@ -6576,11 +7077,11 @@
7077 if( aIdx[3]==0 ){
7078 /* Ignore OFFSET if LIMIT is omitted */
7079 idxNum &= ~0x60;
7080 aIdx[4] = 0;
7081 }
7082 for(i=0; i<7; i++){
7083 if( (j = aIdx[i])>=0 ){
7084 pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg;
7085 pIdxInfo->aConstraintUsage[j].omit =
7086 !SQLITE_SERIES_CONSTRAINT_VERIFY || i>=3;
7087 }
@@ -6624,10 +7125,13 @@
7125 ** of numbers. Make this case very expensive so that the query
7126 ** planner will work hard to avoid it. */
7127 pIdxInfo->estimatedRows = 2147483647;
7128 }
7129 pIdxInfo->idxNum = idxNum;
7130 #ifdef SQLITE_INDEX_SCAN_HEX
7131 pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_HEX;
7132 #endif
7133 return SQLITE_OK;
7134 }
7135
7136 /*
7137 ** This following structure defines all the methods for the
@@ -22175,14 +22679,15 @@
22679 sqlite3_bind_double(pStmt, i, INFINITY);
22680 #endif
22681 }else if( strncmp(zVar, "$int_", 5)==0 ){
22682 sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));
22683 }else if( strncmp(zVar, "$text_", 6)==0 ){
22684 size_t szVar = strlen(zVar);
22685 char *zBuf = sqlite3_malloc64( szVar-5 );
22686 if( zBuf ){
22687 memcpy(zBuf, &zVar[6], szVar-5);
22688 sqlite3_bind_text64(pStmt, i, zBuf, szVar-6, sqlite3_free, SQLITE_UTF8);
22689 }
22690 }else{
22691 sqlite3_bind_null(pStmt, i);
22692 }
22693 sqlite3_reset(pQ);
@@ -24970,16 +25475,21 @@
25475 oputf("%-20s %u\n", "data version", iDataVersion);
25476 return 0;
25477 }
25478 #endif /* SQLITE_SHELL_HAVE_RECOVER */
25479
25480 /*
25481 ** Print the given string as an error message.
25482 */
25483 static void shellEmitError(const char *zErr){
25484 eputf("Error: %s\n", zErr);
25485 }
25486 /*
25487 ** Print the current sqlite3_errmsg() value to stderr and return 1.
25488 */
25489 static int shellDatabaseError(sqlite3 *db){
25490 shellEmitError(sqlite3_errmsg(db));
 
25491 return 1;
25492 }
25493
25494 /*
25495 ** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
@@ -25520,11 +26030,11 @@
26030 va_list ap;
26031 char *z;
26032 va_start(ap, zFmt);
26033 z = sqlite3_vmprintf(zFmt, ap);
26034 va_end(ap);
26035 shellEmitError(z);
26036 if( pAr->fromCmdLine ){
26037 eputz("Use \"-A\" for more help\n");
26038 }else{
26039 eputz("Use \".archive --help\" for more help\n");
26040 }
@@ -26751,20 +27261,20 @@
27261 0, 0, 0);
27262 }
27263 open_db(p, 0);
27264 pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
27265 if( pBackup==0 ){
27266 shellDatabaseError(pDest);
27267 close_db(pDest);
27268 return 1;
27269 }
27270 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
27271 sqlite3_backup_finish(pBackup);
27272 if( rc==SQLITE_DONE ){
27273 rc = 0;
27274 }else{
27275 shellDatabaseError(pDest);
27276 rc = 1;
27277 }
27278 close_db(pDest);
27279 }else
27280 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -26936,11 +27446,11 @@
27446 sqlite3_stmt *pStmt;
27447 int i;
27448 open_db(p, 0);
27449 rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
27450 if( rc ){
27451 shellDatabaseError(p->db);
27452 rc = 1;
27453 }else{
27454 while( sqlite3_step(pStmt)==SQLITE_ROW ){
27455 const char *zSchema = (const char *)sqlite3_column_text(pStmt,1);
27456 const char *zFile = (const char*)sqlite3_column_text(pStmt,2);
@@ -27632,11 +28142,11 @@
28142 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
28143 sqlite3_free(zSql);
28144 zSql = 0;
28145 if( rc ){
28146 if (pStmt) sqlite3_finalize(pStmt);
28147 shellDatabaseError(p->db);
28148 import_cleanup(&sCtx);
28149 rc = 1;
28150 goto meta_command_exit;
28151 }
28152 if( sqlite3_step(pStmt)==SQLITE_ROW ){
@@ -27676,11 +28186,11 @@
28186 }
28187 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
28188 sqlite3_free(zSql);
28189 zSql = 0;
28190 if( rc ){
28191 shellDatabaseError(p->db);
28192 if (pStmt) sqlite3_finalize(pStmt);
28193 import_cleanup(&sCtx);
28194 rc = 1;
28195 goto meta_command_exit;
28196 }
@@ -27970,11 +28480,11 @@
28480 zFile = azArg[1];
28481 zProc = nArg>=3 ? azArg[2] : 0;
28482 open_db(p, 0);
28483 rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
28484 if( rc!=SQLITE_OK ){
28485 shellEmitError(zErrMsg);
28486 sqlite3_free(zErrMsg);
28487 rc = 1;
28488 }
28489 }else
28490 #endif
@@ -28592,11 +29102,11 @@
29102 return 1;
29103 }
29104 open_db(p, 0);
29105 pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
29106 if( pBackup==0 ){
29107 shellDatabaseError(p->db);
29108 close_db(pSrc);
29109 return 1;
29110 }
29111 while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
29112 || rc==SQLITE_BUSY ){
@@ -28610,11 +29120,11 @@
29120 rc = 0;
29121 }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
29122 eputz("Error: source database is busy\n");
29123 rc = 1;
29124 }else{
29125 shellDatabaseError(p->db);
29126 rc = 1;
29127 }
29128 close_db(pSrc);
29129 }else
29130 #endif /* !defined(SQLITE_SHELL_FIDDLE) */
@@ -28707,11 +29217,11 @@
29217 if( zDiv ){
29218 sqlite3_stmt *pStmt = 0;
29219 rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
29220 -1, &pStmt, 0);
29221 if( rc ){
29222 shellDatabaseError(p->db);
29223 sqlite3_finalize(pStmt);
29224 rc = 1;
29225 goto meta_command_exit;
29226 }
29227 appendText(&sSelect, "SELECT sql FROM", 0);
@@ -28776,11 +29286,11 @@
29286 rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
29287 }
29288 freeText(&sSelect);
29289 }
29290 if( zErrMsg ){
29291 shellEmitError(zErrMsg);
29292 sqlite3_free(zErrMsg);
29293 rc = 1;
29294 }else if( rc != SQLITE_OK ){
29295 eputz("Error: querying schema information\n");
29296 rc = 1;
@@ -29547,11 +30057,11 @@
30057 {"imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"},
30058 {"internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" },
30059 {"json_selfcheck", SQLITE_TESTCTRL_JSON_SELFCHECK ,0,"BOOLEAN" },
30060 {"localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" },
30061 {"never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" },
30062 {"optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK ..."},
30063 #ifdef YYCOVERAGE
30064 {"parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" },
30065 #endif
30066 {"pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,1, "OFFSET " },
30067 {"prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" },
@@ -29610,13 +30120,123 @@
30120 if( testctrl<0 ){
30121 eputf("Error: unknown test-control: %s\n"
30122 "Use \".testctrl --help\" for help\n", zCmd);
30123 }else{
30124 switch(testctrl){
30125
30126 /* Special processing for .testctrl opt MASK ...
30127 ** Each MASK argument can be one of:
30128 **
30129 ** +LABEL Enable the named optimization
30130 **
30131 ** -LABEL Disable the named optimization
30132 **
30133 ** INTEGER Mask of optimizations to disable
30134 */
30135 case SQLITE_TESTCTRL_OPTIMIZATIONS: {
30136 static const struct {
30137 unsigned int mask; /* Mask for this optimization */
30138 unsigned int bDsply; /* Display this on output */
30139 const char *zLabel; /* Name of optimization */
30140 } aLabel[] = {
30141 { 0x00000001, 1, "QueryFlattener" },
30142 { 0x00000001, 0, "Flatten" },
30143 { 0x00000002, 1, "WindowFunc" },
30144 { 0x00000004, 1, "GroupByOrder" },
30145 { 0x00000008, 1, "FactorOutConst" },
30146 { 0x00000010, 1, "DistinctOpt" },
30147 { 0x00000020, 1, "CoverIdxScan" },
30148 { 0x00000040, 1, "OrderByIdxJoin" },
30149 { 0x00000080, 1, "Transitive" },
30150 { 0x00000100, 1, "OmitNoopJoin" },
30151 { 0x00000200, 1, "CountOfView" },
30152 { 0x00000400, 1, "CurosrHints" },
30153 { 0x00000800, 1, "Stat4" },
30154 { 0x00001000, 1, "PushDown" },
30155 { 0x00002000, 1, "SimplifyJoin" },
30156 { 0x00004000, 1, "SkipScan" },
30157 { 0x00008000, 1, "PropagateConst" },
30158 { 0x00010000, 1, "MinMaxOpt" },
30159 { 0x00020000, 1, "SeekScan" },
30160 { 0x00040000, 1, "OmitOrderBy" },
30161 { 0x00080000, 1, "BloomFilter" },
30162 { 0x00100000, 1, "BloomPulldown" },
30163 { 0x00200000, 1, "BalancedMerge" },
30164 { 0x00400000, 1, "ReleaseReg" },
30165 { 0x00800000, 1, "FlttnUnionAll" },
30166 { 0x01000000, 1, "IndexedEXpr" },
30167 { 0x02000000, 1, "Coroutines" },
30168 { 0x04000000, 1, "NullUnusedCols" },
30169 { 0x08000000, 1, "OnePass" },
30170 { 0x10000000, 1, "OrderBySubq" },
30171 { 0xffffffff, 0, "All" },
30172 };
30173 unsigned int curOpt;
30174 unsigned int newOpt;
30175 int ii;
30176 sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, p->db, &curOpt);
30177 newOpt = curOpt;
30178 for(ii=2; ii<nArg; ii++){
30179 const char *z = azArg[ii];
30180 int useLabel = 0;
30181 const char *zLabel = 0;
30182 if( (z[0]=='+'|| z[0]=='-') && !IsDigit(z[1]) ){
30183 useLabel = z[0];
30184 zLabel = &z[1];
30185 }else if( !IsDigit(z[0]) && z[0]!=0 && !IsDigit(z[1]) ){
30186 useLabel = '+';
30187 zLabel = z;
30188 }else{
30189 newOpt = (unsigned int)strtol(z,0,0);
30190 }
30191 if( useLabel ){
30192 int jj;
30193 for(jj=0; jj<ArraySize(aLabel); jj++){
30194 if( sqlite3_stricmp(zLabel, aLabel[jj].zLabel)==0 ) break;
30195 }
30196 if( jj>=ArraySize(aLabel) ){
30197 eputf("Error: no such optimization: \"%s\"\n", zLabel);
30198 eputz("Should be one of:");
30199 for(jj=0; jj<ArraySize(aLabel); jj++){
30200 eputf(" %s", aLabel[jj].zLabel);
30201 }
30202 eputz("\n");
30203 rc = 1;
30204 goto meta_command_exit;
30205 }
30206 if( useLabel=='+' ){
30207 newOpt &= ~aLabel[jj].mask;
30208 }else{
30209 newOpt |= aLabel[jj].mask;
30210 }
30211 }
30212 }
30213 if( curOpt!=newOpt ){
30214 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,p->db,newOpt);
30215 }else if( nArg<3 ){
30216 curOpt = ~newOpt;
30217 }
30218 if( newOpt==0 ){
30219 oputz("+All\n");
30220 }else if( newOpt==0xffffffff ){
30221 oputz("-All\n");
30222 }else{
30223 int jj;
30224 for(jj=0; jj<ArraySize(aLabel); jj++){
30225 unsigned int m = aLabel[jj].mask;
30226 if( !aLabel[jj].bDsply ) continue;
30227 if( (curOpt&m)!=(newOpt&m) ){
30228 oputf("%c%s\n", (newOpt & m)==0 ? '+' : '-',
30229 aLabel[jj].zLabel);
30230 }
30231 }
30232 }
30233 rc2 = isOk = 3;
30234 break;
30235 }
30236
30237 /* sqlite3_test_control(int, db, int) */
 
30238 case SQLITE_TESTCTRL_FK_NO_ACTION:
30239 if( nArg==3 ){
30240 unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0);
30241 rc2 = sqlite3_test_control(testctrl, p->db, opt);
30242 isOk = 3;
@@ -31355,11 +31975,11 @@
31975 if( rc && bail_on_error ) return rc==2 ? 0 : rc;
31976 }else{
31977 open_db(&data, 0);
31978 rc = shell_exec(&data, z, &zErrMsg);
31979 if( zErrMsg!=0 ){
31980 shellEmitError(zErrMsg);
31981 if( bail_on_error ) return rc!=0 ? rc : 1;
31982 }else if( rc!=0 ){
31983 eputf("Error: unable to process SQL \"%s\"\n", z);
31984 if( bail_on_error ) return rc;
31985 }
@@ -31409,11 +32029,11 @@
32029 open_db(&data, 0);
32030 echo_group_input(&data, azCmd[i]);
32031 rc = shell_exec(&data, azCmd[i], &zErrMsg);
32032 if( zErrMsg || rc ){
32033 if( zErrMsg!=0 ){
32034 shellEmitError(zErrMsg);
32035 }else{
32036 eputf("Error: unable to process SQL: %s\n", azCmd[i]);
32037 }
32038 sqlite3_free(zErrMsg);
32039 if( rc==0 ) rc = 1;
32040
+2338 -703
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -16,11 +16,11 @@
1616
** if you want a wrapper to interface SQLite with your choice of programming
1717
** language. The code for the "sqlite3" command-line shell is also in a
1818
** separate file. This file contains only code for the core SQLite library.
1919
**
2020
** The content in this amalgamation comes from Fossil check-in
21
-** 7a0cdc7edb704a88a77b748cd28f6e00c498.
21
+** 7891a266c4425722ae8b9231397ef9e42e24.
2222
*/
2323
#define SQLITE_CORE 1
2424
#define SQLITE_AMALGAMATION 1
2525
#ifndef SQLITE_PRIVATE
2626
# define SQLITE_PRIVATE static
@@ -462,11 +462,11 @@
462462
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
463463
** [sqlite_version()] and [sqlite_source_id()].
464464
*/
465465
#define SQLITE_VERSION "3.47.0"
466466
#define SQLITE_VERSION_NUMBER 3047000
467
-#define SQLITE_SOURCE_ID "2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9"
467
+#define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
468468
469469
/*
470470
** CAPI3REF: Run-Time Library Version Numbers
471471
** KEYWORDS: sqlite3_version sqlite3_sourceid
472472
**
@@ -5929,18 +5929,28 @@
59295929
** might become a no-op if the function is used as term in an
59305930
** [expression index]. On the other hand, SQL functions that never invoke
59315931
** [sqlite3_result_subtype()] should avoid setting this property, as the
59325932
** purpose of this property is to disable certain optimizations that are
59335933
** incompatible with subtypes.
5934
+**
5935
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
5936
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
5937
+** that internally orders the values provided to the first argument. The
5938
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
5939
+** used to invoke this function. If the ordered-set aggregate notation is
5940
+** used on a function that lacks this flag, then an error is raised. Note
5941
+** that the ordered-set aggregate syntax is only available if SQLite is
5942
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
59345943
** </dd>
59355944
** </dl>
59365945
*/
59375946
#define SQLITE_DETERMINISTIC 0x000000800
59385947
#define SQLITE_DIRECTONLY 0x000080000
59395948
#define SQLITE_SUBTYPE 0x000100000
59405949
#define SQLITE_INNOCUOUS 0x000200000
59415950
#define SQLITE_RESULT_SUBTYPE 0x001000000
5951
+#define SQLITE_SELFORDER1 0x002000000
59425952
59435953
/*
59445954
** CAPI3REF: Deprecated Functions
59455955
** DEPRECATED
59465956
**
@@ -7741,13 +7751,15 @@
77417751
**
77427752
** ^The estimatedRows value is an estimate of the number of rows that
77437753
** will be returned by the strategy.
77447754
**
77457755
** The xBestIndex method may optionally populate the idxFlags field with a
7746
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
7747
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
7748
-** assumes that the strategy may visit at most one row.
7756
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
7757
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
7758
+** output to show the idxNum has hex instead of as decimal. Another flag is
7759
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
7760
+** return at most one row.
77497761
**
77507762
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
77517763
** SQLite also assumes that if a call to the xUpdate() method is made as
77527764
** part of the same statement to delete or update a virtual table row and the
77537765
** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7807,11 +7819,13 @@
78077819
**
78087820
** Virtual table implementations are allowed to set the
78097821
** [sqlite3_index_info].idxFlags field to some combination of
78107822
** these bits.
78117823
*/
7812
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
7824
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
7825
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
7826
+ /* in EXPLAIN QUERY PLAN */
78137827
78147828
/*
78157829
** CAPI3REF: Virtual Table Constraint Operator Codes
78167830
**
78177831
** These macros define the allowed values for the
@@ -8644,10 +8658,11 @@
86448658
#define SQLITE_TESTCTRL_ALWAYS 13
86458659
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
86468660
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
86478661
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
86488662
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
8663
+#define SQLITE_TESTCTRL_GETOPT 16
86498664
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
86508665
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
86518666
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
86528667
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
86538668
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13418,13 +13433,36 @@
1341813433
** It is the output of the tokenizer module. For tokendata=1 tables, this
1341913434
** includes any embedded 0x00 and trailing data.
1342013435
**
1342113436
** This API can be quite slow if used with an FTS5 table created with the
1342213437
** "detail=none" or "detail=column" option.
13438
+**
13439
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
13440
+** If parameter iCol is less than zero, or greater than or equal to the
13441
+** number of columns in the table, SQLITE_RANGE is returned.
13442
+**
13443
+** Otherwise, this function attempts to retrieve the locale associated
13444
+** with column iCol of the current row. Usually, there is no associated
13445
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
13446
+** to NULL and 0, respectively. However, if the fts5_locale() function
13447
+** was used to associate a locale with the value when it was inserted
13448
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
13449
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
13450
+** is set to the size in bytes of the buffer, not including the
13451
+** nul-terminator.
13452
+**
13453
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
13454
+** SQLite error code is returned. The final value of the output parameters
13455
+** is undefined in this case.
13456
+**
13457
+** xTokenize_v2:
13458
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
13459
+** API is the same as the xTokenize() API, except that it allows a tokenizer
13460
+** locale to be specified.
1342313461
*/
1342413462
struct Fts5ExtensionApi {
13425
- int iVersion; /* Currently always set to 3 */
13463
+ int iVersion; /* Currently always set to 4 */
1342613464
1342713465
void *(*xUserData)(Fts5Context*);
1342813466
1342913467
int (*xColumnCount)(Fts5Context*);
1343013468
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13462,10 +13500,19 @@
1346213500
int (*xQueryToken)(Fts5Context*,
1346313501
int iPhrase, int iToken,
1346413502
const char **ppToken, int *pnToken
1346513503
);
1346613504
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
13505
+
13506
+ /* Below this point are iVersion>=4 only */
13507
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
13508
+ int (*xTokenize_v2)(Fts5Context*,
13509
+ const char *pText, int nText, /* Text to tokenize */
13510
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
13511
+ void *pCtx, /* Context passed to xToken() */
13512
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
13513
+ );
1346713514
};
1346813515
1346913516
/*
1347013517
** CUSTOM AUXILIARY FUNCTIONS
1347113518
*************************************************************************/
@@ -13474,19 +13521,20 @@
1347413521
** CUSTOM TOKENIZERS
1347513522
**
1347613523
** Applications may also register custom tokenizer types. A tokenizer
1347713524
** is registered by providing fts5 with a populated instance of the
1347813525
** following structure. All structure methods must be defined, setting
13526
+**
1347913527
** any member of the fts5_tokenizer struct to NULL leads to undefined
1348013528
** behaviour. The structure methods are expected to function as follows:
1348113529
**
1348213530
** xCreate:
1348313531
** This function is used to allocate and initialize a tokenizer instance.
1348413532
** A tokenizer instance is required to actually tokenize text.
1348513533
**
1348613534
** The first argument passed to this function is a copy of the (void*)
13487
-** pointer provided by the application when the fts5_tokenizer object
13535
+** pointer provided by the application when the fts5_tokenizer_v2 object
1348813536
** was registered with FTS5 (the third argument to xCreateTokenizer()).
1348913537
** The second and third arguments are an array of nul-terminated strings
1349013538
** containing the tokenizer arguments, if any, specified following the
1349113539
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
1349213540
** to create the FTS5 table.
@@ -13506,11 +13554,11 @@
1350613554
** This function is expected to tokenize the nText byte string indicated
1350713555
** by argument pText. pText may or may not be nul-terminated. The first
1350813556
** argument passed to this function is a pointer to an Fts5Tokenizer object
1350913557
** returned by an earlier call to xCreate().
1351013558
**
13511
-** The second argument indicates the reason that FTS5 is requesting
13559
+** The third argument indicates the reason that FTS5 is requesting
1351213560
** tokenization of the supplied text. This is always one of the following
1351313561
** four values:
1351413562
**
1351513563
** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
1351613564
** or removed from the FTS table. The tokenizer is being invoked to
@@ -13529,10 +13577,17 @@
1352913577
** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
1353013578
** satisfy an fts5_api.xTokenize() request made by an auxiliary
1353113579
** function. Or an fts5_api.xColumnSize() request made by the same
1353213580
** on a columnsize=0 database.
1353313581
** </ul>
13582
+**
13583
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
13584
+** nLocale - are a pointer to a buffer containing the locale to use for
13585
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
13586
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
13587
+** which case nLocale is always 0) to indicate that the tokenizer should
13588
+** use its default locale.
1353413589
**
1353513590
** For each token in the input string, the supplied callback xToken() must
1353613591
** be invoked. The first argument to it should be a copy of the pointer
1353713592
** passed as the second argument to xTokenize(). The third and fourth
1353813593
** arguments are a pointer to a buffer containing the token text, and the
@@ -13552,10 +13607,34 @@
1355213607
** immediately return a copy of the xToken() return value. Or, if the
1355313608
** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
1355413609
** if an error occurs with the xTokenize() implementation itself, it
1355513610
** may abandon the tokenization and return any error code other than
1355613611
** SQLITE_OK or SQLITE_DONE.
13612
+**
13613
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
13614
+** then the xTokenize() method has two additional arguments - pLocale
13615
+** and nLocale. These specify the locale that the tokenizer should use
13616
+** for the current request. If pLocale and nLocale are both 0, then the
13617
+** tokenizer should use its default locale. Otherwise, pLocale points to
13618
+** an nLocale byte buffer containing the name of the locale to use as utf-8
13619
+** text. pLocale is not nul-terminated.
13620
+**
13621
+** FTS5_TOKENIZER
13622
+**
13623
+** There is also an fts5_tokenizer object. This is an older, deprecated,
13624
+** version of fts5_tokenizer_v2. It is similar except that:
13625
+**
13626
+** <ul>
13627
+** <li> There is no "iVersion" field, and
13628
+** <li> The xTokenize() method does not take a locale argument.
13629
+** </ul>
13630
+**
13631
+** Legacy fts5_tokenizer tokenizers must be registered using the
13632
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
13633
+**
13634
+** Tokenizer implementations registered using either API may be retrieved
13635
+** using both xFindTokenizer() and xFindTokenizer_v2().
1355713636
**
1355813637
** SYNONYM SUPPORT
1355913638
**
1356013639
** Custom tokenizers may also support synonyms. Consider a case in which a
1356113640
** user wishes to query for a phrase such as "first place". Using the
@@ -13661,10 +13740,37 @@
1366113740
** provide synonyms when tokenizing document text (method (3)) or query
1366213741
** text (method (2)), not both. Doing so will not cause any errors, but is
1366313742
** inefficient.
1366413743
*/
1366513744
typedef struct Fts5Tokenizer Fts5Tokenizer;
13745
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
13746
+struct fts5_tokenizer_v2 {
13747
+ int iVersion; /* Currently always 2 */
13748
+
13749
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13750
+ void (*xDelete)(Fts5Tokenizer*);
13751
+ int (*xTokenize)(Fts5Tokenizer*,
13752
+ void *pCtx,
13753
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
13754
+ const char *pText, int nText,
13755
+ const char *pLocale, int nLocale,
13756
+ int (*xToken)(
13757
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
13758
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
13759
+ const char *pToken, /* Pointer to buffer containing token */
13760
+ int nToken, /* Size of token in bytes */
13761
+ int iStart, /* Byte offset of token within input text */
13762
+ int iEnd /* Byte offset of end of token within input text */
13763
+ )
13764
+ );
13765
+};
13766
+
13767
+/*
13768
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
13769
+** implementations. The following type is included for legacy applications
13770
+** that still use it.
13771
+*/
1366613772
typedef struct fts5_tokenizer fts5_tokenizer;
1366713773
struct fts5_tokenizer {
1366813774
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
1366913775
void (*xDelete)(Fts5Tokenizer*);
1367013776
int (*xTokenize)(Fts5Tokenizer*,
@@ -13679,10 +13785,11 @@
1367913785
int iStart, /* Byte offset of token within input text */
1368013786
int iEnd /* Byte offset of end of token within input text */
1368113787
)
1368213788
);
1368313789
};
13790
+
1368413791
1368513792
/* Flags that may be passed as the third argument to xTokenize() */
1368613793
#define FTS5_TOKENIZE_QUERY 0x0001
1368713794
#define FTS5_TOKENIZE_PREFIX 0x0002
1368813795
#define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13699,11 +13806,11 @@
1369913806
/*************************************************************************
1370013807
** FTS5 EXTENSION REGISTRATION API
1370113808
*/
1370213809
typedef struct fts5_api fts5_api;
1370313810
struct fts5_api {
13704
- int iVersion; /* Currently always set to 2 */
13811
+ int iVersion; /* Currently always set to 3 */
1370513812
1370613813
/* Create a new tokenizer */
1370713814
int (*xCreateTokenizer)(
1370813815
fts5_api *pApi,
1370913816
const char *zName,
@@ -13726,10 +13833,29 @@
1372613833
const char *zName,
1372713834
void *pUserData,
1372813835
fts5_extension_function xFunction,
1372913836
void (*xDestroy)(void*)
1373013837
);
13838
+
13839
+ /* APIs below this point are only available if iVersion>=3 */
13840
+
13841
+ /* Create a new tokenizer */
13842
+ int (*xCreateTokenizer_v2)(
13843
+ fts5_api *pApi,
13844
+ const char *zName,
13845
+ void *pUserData,
13846
+ fts5_tokenizer_v2 *pTokenizer,
13847
+ void (*xDestroy)(void*)
13848
+ );
13849
+
13850
+ /* Find an existing tokenizer */
13851
+ int (*xFindTokenizer_v2)(
13852
+ fts5_api *pApi,
13853
+ const char *zName,
13854
+ void **ppUserData,
13855
+ fts5_tokenizer_v2 **ppTokenizer
13856
+ );
1373113857
};
1373213858
1373313859
/*
1373413860
** END OF REGISTRATION API
1373513861
*************************************************************************/
@@ -14703,10 +14829,12 @@
1470314829
** substitute integer for floating-point
1470414830
*/
1470514831
#ifdef SQLITE_OMIT_FLOATING_POINT
1470614832
# define double sqlite_int64
1470714833
# define float sqlite_int64
14834
+# define fabs(X) ((X)<0?-(X):(X))
14835
+# define sqlite3IsOverflow(X) 0
1470814836
# define LONGDOUBLE_TYPE sqlite_int64
1470914837
# ifndef SQLITE_BIG_DBL
1471014838
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
1471114839
# endif
1471214840
# define SQLITE_OMIT_DATETIME_FUNCS 1
@@ -15380,10 +15508,11 @@
1538015508
typedef struct RowSet RowSet;
1538115509
typedef struct Savepoint Savepoint;
1538215510
typedef struct Select Select;
1538315511
typedef struct SQLiteThread SQLiteThread;
1538415512
typedef struct SelectDest SelectDest;
15513
+typedef struct Subquery Subquery;
1538515514
typedef struct SrcItem SrcItem;
1538615515
typedef struct SrcList SrcList;
1538715516
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
1538815517
typedef struct Table Table;
1538915518
typedef struct TableLock TableLock;
@@ -19263,10 +19392,20 @@
1926319392
*/
1926419393
#define EU4_NONE 0 /* Does not use IdList.a.u4 */
1926519394
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
1926619395
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
1926719396
19397
+/*
19398
+** Details of the implementation of a subquery.
19399
+*/
19400
+struct Subquery {
19401
+ Select *pSelect; /* A SELECT statement used in place of a table name */
19402
+ int addrFillSub; /* Address of subroutine to initialize a subquery */
19403
+ int regReturn; /* Register holding return address of addrFillSub */
19404
+ int regResult; /* Registers holding results of a co-routine */
19405
+};
19406
+
1926819407
/*
1926919408
** The SrcItem object represents a single term in the FROM clause of a query.
1927019409
** The SrcList object is mostly an array of SrcItems.
1927119410
**
1927219411
** The jointype starts out showing the join type between the current table
@@ -19275,33 +19414,44 @@
1927519414
** jointype expresses the join between the table and the previous table.
1927619415
**
1927719416
** In the colUsed field, the high-order bit (bit 63) is set if the table
1927819417
** contains more than 63 columns and the 64-th or later column is used.
1927919418
**
19280
-** Union member validity:
19419
+** Aggressive use of "union" helps keep the size of the object small. This
19420
+** has been shown to boost performance, in addition to saving memory.
19421
+** Access to union elements is gated by the following rules which should
19422
+** always be checked, either by an if-statement or by an assert().
1928119423
**
19282
-** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
19283
-** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
19424
+** Field Only access if this is true
19425
+** --------------- -----------------------------------
19426
+** u1.zIndexedBy fg.isIndexedBy
19427
+** u1.pFuncArg fg.isTabFunc
1928419428
** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
1928519429
**
19286
-** u2.pIBIndex fg.isIndexedBy && !fg.isCte
19287
-** u2.pCteUse fg.isCte && !fg.isIndexedBy
19430
+** u2.pIBIndex fg.isIndexedBy
19431
+** u2.pCteUse fg.isCte
19432
+**
19433
+** u3.pOn !fg.isUsing
19434
+** u3.pUsing fg.isUsing
19435
+**
19436
+** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
19437
+** u4.pSchema fg.fixedSchema
19438
+** u4.pSubq fg.isSubquery
19439
+**
19440
+** See also the sqlite3SrcListDelete() routine for assert() statements that
19441
+** check invariants on the fields of this object, especially the flags
19442
+** inside the fg struct.
1928819443
*/
1928919444
struct SrcItem {
19290
- Schema *pSchema; /* Schema to which this item is fixed */
19291
- char *zDatabase; /* Name of database holding this table */
1929219445
char *zName; /* Name of the table */
1929319446
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
19294
- Table *pTab; /* An SQL table corresponding to zName */
19295
- Select *pSelect; /* A SELECT statement used in place of a table name */
19296
- int addrFillSub; /* Address of subroutine to manifest a subquery */
19297
- int regReturn; /* Register holding return address of addrFillSub */
19298
- int regResult; /* Registers holding results of a co-routine */
19447
+ Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
1929919448
struct {
1930019449
u8 jointype; /* Type of join between this table and the previous */
1930119450
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
1930219451
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
19452
+ unsigned isSubquery :1; /* True if this term is a subquery */
1930319453
unsigned isTabFunc :1; /* True if table-valued-function syntax */
1930419454
unsigned isCorrelated :1; /* True if sub-query is correlated */
1930519455
unsigned isMaterialized:1; /* This is a materialized view */
1930619456
unsigned viaCoroutine :1; /* Implemented as a co-routine */
1930719457
unsigned isRecursive :1; /* True for recursive reference in WITH */
@@ -19311,16 +19461,14 @@
1931119461
unsigned isUsing :1; /* u3.pUsing is valid */
1931219462
unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
1931319463
unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
1931419464
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
1931519465
unsigned rowidUsed :1; /* The ROWID of this table is referenced */
19466
+ unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
19467
+ unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
1931619468
} fg;
1931719469
int iCursor; /* The VDBE cursor number used to access this table */
19318
- union {
19319
- Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
19320
- IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
19321
- } u3;
1932219470
Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
1932319471
union {
1932419472
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
1932519473
ExprList *pFuncArg; /* Arguments to table-valued-function */
1932619474
u32 nRow; /* Number of rows in a VALUES clause */
@@ -19327,10 +19475,19 @@
1932719475
} u1;
1932819476
union {
1932919477
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
1933019478
CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
1933119479
} u2;
19480
+ union {
19481
+ Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
19482
+ IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
19483
+ } u3;
19484
+ union {
19485
+ Schema *pSchema; /* Schema to which this item is fixed */
19486
+ char *zDatabase; /* Name of database holding this table */
19487
+ Subquery *pSubq; /* Description of a subquery */
19488
+ } u4;
1933219489
};
1933319490
1933419491
/*
1933519492
** The OnOrUsing object represents either an ON clause or a USING clause.
1933619493
** It can never be both at the same time, but it can be neither.
@@ -19586,12 +19743,14 @@
1958619743
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
1958719744
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
1958819745
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
1958919746
#define SF_Correlated 0x20000000 /* True if references the outer context */
1959019747
19591
-/* True if S exists and has SF_NestedFrom */
19592
-#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
19748
+/* True if SrcItem X is a subquery that has SF_NestedFrom */
19749
+#define IsNestedFrom(X) \
19750
+ ((X)->fg.isSubquery && \
19751
+ ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
1959319752
1959419753
/*
1959519754
** The results of a SELECT can be distributed in several ways, as defined
1959619755
** by one of the following macros. The "SRT" prefix means "SELECT Result
1959719756
** Type".
@@ -20979,10 +21138,13 @@
2097921138
SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
2098021139
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
2098121140
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
2098221141
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
2098321142
SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
21143
+SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3*,Subquery*);
21144
+SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*);
21145
+SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
2098421146
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
2098521147
Token*, Select*, OnOrUsing*);
2098621148
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
2098721149
SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
2098821150
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *);
@@ -22204,10 +22366,13 @@
2220422366
#ifdef SQLITE_ENABLE_NULL_TRIM
2220522367
"ENABLE_NULL_TRIM",
2220622368
#endif
2220722369
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
2220822370
"ENABLE_OFFSET_SQL_FUNC",
22371
+#endif
22372
+#ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
22373
+ "ENABLE_ORDERED_SET_AGGREGATES",
2220922374
#endif
2221022375
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
2221122376
"ENABLE_OVERSIZE_CELL_CHECK",
2221222377
#endif
2221322378
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -24521,12 +24686,12 @@
2452124686
}
2452224687
if( M<=2 ){
2452324688
Y--;
2452424689
M += 12;
2452524690
}
24526
- A = Y/100;
24527
- B = 2 - A + (A/4);
24691
+ A = (Y+4800)/100;
24692
+ B = 38 - A + (A/4);
2452824693
X1 = 36525*(Y+4716)/100;
2452924694
X2 = 306001*(M+1)/10000;
2453024695
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
2453124696
p->validJD = 1;
2453224697
if( p->validHMS ){
@@ -24706,11 +24871,11 @@
2470624871
2470724872
/*
2470824873
** Compute the Year, Month, and Day from the julian day number.
2470924874
*/
2471024875
static void computeYMD(DateTime *p){
24711
- int Z, A, B, C, D, E, X1;
24876
+ int Z, alpha, A, B, C, D, E, X1;
2471224877
if( p->validYMD ) return;
2471324878
if( !p->validJD ){
2471424879
p->Y = 2000;
2471524880
p->M = 1;
2471624881
p->D = 1;
@@ -24717,12 +24882,12 @@
2471724882
}else if( !validJulianDay(p->iJD) ){
2471824883
datetimeError(p);
2471924884
return;
2472024885
}else{
2472124886
Z = (int)((p->iJD + 43200000)/86400000);
24722
- A = (int)((Z - 1867216.25)/36524.25);
24723
- A = Z + 1 + A - (A/4);
24887
+ alpha = (int)((Z + 32044.75)/36524.25) - 52;
24888
+ A = Z + 1 + alpha - ((alpha+100)/4) + 25;
2472424889
B = A + 1524;
2472524890
C = (int)((B - 122.1)/365.25);
2472624891
D = (36525*(C&32767))/100;
2472724892
E = (int)((B-D)/30.6001);
2472824893
X1 = (int)(30.6001*E);
@@ -32017,20 +32182,23 @@
3201732182
pItem = va_arg(ap, SrcItem*);
3201832183
assert( bArgList==0 );
3201932184
if( pItem->zAlias && !flag_altform2 ){
3202032185
sqlite3_str_appendall(pAccum, pItem->zAlias);
3202132186
}else if( pItem->zName ){
32022
- if( pItem->zDatabase ){
32023
- sqlite3_str_appendall(pAccum, pItem->zDatabase);
32187
+ if( pItem->fg.fixedSchema==0
32188
+ && pItem->fg.isSubquery==0
32189
+ && pItem->u4.zDatabase!=0
32190
+ ){
32191
+ sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
3202432192
sqlite3_str_append(pAccum, ".", 1);
3202532193
}
3202632194
sqlite3_str_appendall(pAccum, pItem->zName);
3202732195
}else if( pItem->zAlias ){
3202832196
sqlite3_str_appendall(pAccum, pItem->zAlias);
32029
- }else{
32030
- Select *pSel = pItem->pSelect;
32031
- assert( pSel!=0 ); /* Because of tag-20240424-1 */
32197
+ }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
32198
+ Select *pSel = pItem->u4.pSubq->pSelect;
32199
+ assert( pSel!=0 );
3203232200
if( pSel->selFlags & SF_NestedFrom ){
3203332201
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
3203432202
}else if( pSel->selFlags & SF_MultiValue ){
3203532203
assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
3203632204
sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
@@ -32808,13 +32976,13 @@
3280832976
int n = 0;
3280932977
char zLine[1000];
3281032978
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
3281132979
x.printfFlags |= SQLITE_PRINTF_INTERNAL;
3281232980
sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
32813
- if( pItem->pTab ){
32981
+ if( pItem->pSTab ){
3281432982
sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
32815
- pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
32983
+ pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
3281632984
pItem->colUsed,
3281732985
pItem->fg.rowidUsed ? "+rowid" : "");
3281832986
}
3281932987
if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
3282032988
sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
@@ -32841,27 +33009,34 @@
3284133009
if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
3284233010
if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
3284333011
if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
3284433012
if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
3284533013
if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
33014
+ if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema");
33015
+ if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema");
33016
+ if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery");
3284633017
3284733018
sqlite3StrAccumFinish(&x);
3284833019
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
3284933020
n = 0;
32850
- if( pItem->pSelect ) n++;
33021
+ if( pItem->fg.isSubquery ) n++;
3285133022
if( pItem->fg.isTabFunc ) n++;
3285233023
if( pItem->fg.isUsing ) n++;
3285333024
if( pItem->fg.isUsing ){
3285433025
sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
3285533026
}
32856
- if( pItem->pSelect ){
32857
- if( pItem->pTab ){
32858
- Table *pTab = pItem->pTab;
33027
+ if( pItem->fg.isSubquery ){
33028
+ assert( n==1 );
33029
+ if( pItem->pSTab ){
33030
+ Table *pTab = pItem->pSTab;
3285933031
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
3286033032
}
32861
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
32862
- sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
33033
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
33034
+ sqlite3TreeViewPush(&pView, 0);
33035
+ sqlite3TreeViewLine(pView, "SUBQUERY");
33036
+ sqlite3TreeViewPop(&pView);
33037
+ sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
3286333038
}
3286433039
if( pItem->fg.isTabFunc ){
3286533040
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
3286633041
}
3286733042
sqlite3TreeViewPop(&pView);
@@ -38721,11 +38896,11 @@
3872138896
** Allowed values for the unixFile.ctrlFlags bitmask:
3872238897
*/
3872338898
#define UNIXFILE_EXCL 0x01 /* Connections from one process only */
3872438899
#define UNIXFILE_RDONLY 0x02 /* Connection is read only */
3872538900
#define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
38726
-#ifndef SQLITE_DISABLE_DIRSYNC
38901
+#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX)
3872738902
# define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
3872838903
#else
3872938904
# define UNIXFILE_DIRSYNC 0x00
3873038905
#endif
3873138906
#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@@ -76573,11 +76748,11 @@
7657376748
}
7657476749
if( pCur->iPage>0
7657576750
&& indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
7657676751
&& pIdxKey->errCode==SQLITE_OK
7657776752
){
76578
- pCur->curFlags &= ~BTCF_ValidOvfl;
76753
+ pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast);
7657976754
if( !pCur->pPage->isInit ){
7658076755
return SQLITE_CORRUPT_BKPT;
7658176756
}
7658276757
goto bypass_moveto_root; /* Start search on the current page */
7658376758
}
@@ -95267,11 +95442,11 @@
9526795442
}
9526895443
break;
9526995444
}
9527095445
#endif
9527195446
95272
-#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
95447
+#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE)
9527395448
/* Opcode: Cast P1 P2 * * *
9527495449
** Synopsis: affinity(r[P1])
9527595450
**
9527695451
** Force the value in register P1 to be the type defined by P2.
9527795452
**
@@ -102547,10 +102722,15 @@
102547102722
}
102548102723
if( pTab && !HasRowid(pTab) ){
102549102724
pTab = 0;
102550102725
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
102551102726
}
102727
+ if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){
102728
+ pTab = 0;
102729
+ sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s",
102730
+ zTable);
102731
+ }
102552102732
#ifndef SQLITE_OMIT_VIEW
102553102733
if( pTab && IsView(pTab) ){
102554102734
pTab = 0;
102555102735
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
102556102736
}
@@ -106731,11 +106911,13 @@
106731106911
SrcItem *pItem;
106732106912
106733106913
pSrc = p->pSrc;
106734106914
if( ALWAYS(pSrc) ){
106735106915
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
106736
- if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
106916
+ if( pItem->fg.isSubquery
106917
+ && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
106918
+ ){
106737106919
return WRC_Abort;
106738106920
}
106739106921
if( pItem->fg.isTabFunc
106740106922
&& sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
106741106923
){
@@ -107037,11 +107219,11 @@
107037107219
){
107038107220
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
107039107221
if( pNew ){
107040107222
pNew->iTable = pMatch->iCursor;
107041107223
pNew->iColumn = iColumn;
107042
- pNew->y.pTab = pMatch->pTab;
107224
+ pNew->y.pTab = pMatch->pSTab;
107043107225
assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
107044107226
ExprSetProperty(pNew, EP_CanBeNull);
107045107227
*ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
107046107228
}
107047107229
}
@@ -107168,24 +107350,28 @@
107168107350
SrcList *pSrcList = pNC->pSrcList;
107169107351
107170107352
if( pSrcList ){
107171107353
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
107172107354
u8 hCol;
107173
- pTab = pItem->pTab;
107355
+ pTab = pItem->pSTab;
107174107356
assert( pTab!=0 && pTab->zName!=0 );
107175107357
assert( pTab->nCol>0 || pParse->nErr );
107176
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
107358
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
107177107359
if( pItem->fg.isNestedFrom ){
107178107360
/* In this case, pItem is a subquery that has been formed from a
107179107361
** parenthesized subset of the FROM clause terms. Example:
107180107362
** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
107181107363
** \_________________________/
107182107364
** This pItem -------------^
107183107365
*/
107184107366
int hit = 0;
107185
- assert( pItem->pSelect!=0 );
107186
- pEList = pItem->pSelect->pEList;
107367
+ Select *pSel;
107368
+ assert( pItem->fg.isSubquery );
107369
+ assert( pItem->u4.pSubq!=0 );
107370
+ pSel = pItem->u4.pSubq->pSelect;
107371
+ assert( pSel!=0 );
107372
+ pEList = pSel->pEList;
107187107373
assert( pEList!=0 );
107188107374
assert( pEList->nExpr==pTab->nCol );
107189107375
for(j=0; j<pEList->nExpr; j++){
107190107376
int bRowid = 0; /* True if possible rowid match */
107191107377
if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
@@ -107305,12 +107491,12 @@
107305107491
** words non-VIEW candidate terms take precedence over VIEWs.
107306107492
*/
107307107493
if( cntTab==0
107308107494
|| (cntTab==1
107309107495
&& ALWAYS(pMatch!=0)
107310
- && ALWAYS(pMatch->pTab!=0)
107311
- && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
107496
+ && ALWAYS(pMatch->pSTab!=0)
107497
+ && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
107312107498
&& (pTab->tabFlags & TF_Ephemeral)==0)
107313107499
){
107314107500
cntTab = 1;
107315107501
pMatch = pItem;
107316107502
}else{
@@ -107327,11 +107513,11 @@
107327107513
}
107328107514
}
107329107515
if( pMatch ){
107330107516
pExpr->iTable = pMatch->iCursor;
107331107517
assert( ExprUseYTab(pExpr) );
107332
- pExpr->y.pTab = pMatch->pTab;
107518
+ pExpr->y.pTab = pMatch->pSTab;
107333107519
if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
107334107520
ExprSetProperty(pExpr, EP_CanBeNull);
107335107521
}
107336107522
pSchema = pExpr->y.pTab->pSchema;
107337107523
}
@@ -107369,11 +107555,11 @@
107369107555
#endif /* SQLITE_OMIT_TRIGGER */
107370107556
#ifndef SQLITE_OMIT_UPSERT
107371107557
if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
107372107558
Upsert *pUpsert = pNC->uNC.pUpsert;
107373107559
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
107374
- pTab = pUpsert->pUpsertSrc->a[0].pTab;
107560
+ pTab = pUpsert->pUpsertSrc->a[0].pSTab;
107375107561
pExpr->iTable = EXCLUDED_TABLE_NUMBER;
107376107562
}
107377107563
}
107378107564
#endif /* SQLITE_OMIT_UPSERT */
107379107565
@@ -107452,15 +107638,15 @@
107452107638
if( cnt==0
107453107639
&& cntTab>=1
107454107640
&& pMatch
107455107641
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
107456107642
&& sqlite3IsRowid(zCol)
107457
- && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
107643
+ && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
107458107644
){
107459107645
cnt = cntTab;
107460107646
#if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
107461
- if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){
107647
+ if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
107462107648
eNewExprOp = TK_NULL;
107463107649
}
107464107650
#endif
107465107651
if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
107466107652
pExpr->affExpr = SQLITE_AFF_INTEGER;
@@ -107693,11 +107879,11 @@
107693107879
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
107694107880
if( p ){
107695107881
SrcItem *pItem = &pSrc->a[iSrc];
107696107882
Table *pTab;
107697107883
assert( ExprUseYTab(p) );
107698
- pTab = p->y.pTab = pItem->pTab;
107884
+ pTab = p->y.pTab = pItem->pSTab;
107699107885
p->iTable = pItem->iCursor;
107700107886
if( p->y.pTab->iPKey==iCol ){
107701107887
p->iColumn = -1;
107702107888
}else{
107703107889
p->iColumn = (ynVar)iCol;
@@ -107812,11 +107998,11 @@
107812107998
SrcItem *pItem;
107813107999
assert( pSrcList && pSrcList->nSrc>=1 );
107814108000
pItem = pSrcList->a;
107815108001
pExpr->op = TK_COLUMN;
107816108002
assert( ExprUseYTab(pExpr) );
107817
- pExpr->y.pTab = pItem->pTab;
108003
+ pExpr->y.pTab = pItem->pSTab;
107818108004
pExpr->iTable = pItem->iCursor;
107819108005
pExpr->iColumn--;
107820108006
pExpr->affExpr = SQLITE_AFF_INTEGER;
107821108007
break;
107822108008
}
@@ -108118,13 +108304,13 @@
108118108304
assert( pExpr->pLeft->op==TK_ORDER );
108119108305
assert( ExprUseXList(pExpr->pLeft) );
108120108306
sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
108121108307
}
108122108308
#ifndef SQLITE_OMIT_WINDOWFUNC
108123
- if( pWin ){
108309
+ if( pWin && pParse->nErr==0 ){
108124108310
Select *pSel = pNC->pWinSelect;
108125
- assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) );
108311
+ assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin );
108126108312
if( IN_RENAME_OBJECT==0 ){
108127108313
sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
108128108314
if( pParse->db->mallocFailed ) break;
108129108315
}
108130108316
sqlite3WalkExprList(pWalker, pWin->pPartition);
@@ -108702,11 +108888,15 @@
108702108888
** In this case the ORDER BY clause (p->pOrderBy) should be resolved
108703108889
** as if it were part of the sub-query, not the parent. This block
108704108890
** moves the pOrderBy down to the sub-query. It will be moved back
108705108891
** after the names have been resolved. */
108706108892
if( p->selFlags & SF_Converted ){
108707
- Select *pSub = p->pSrc->a[0].pSelect;
108893
+ Select *pSub;
108894
+ assert( p->pSrc->a[0].fg.isSubquery );
108895
+ assert( p->pSrc->a[0].u4.pSubq!=0 );
108896
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
108897
+ assert( pSub!=0 );
108708108898
assert( p->pSrc->nSrc==1 && p->pOrderBy );
108709108899
assert( pSub->pPrior && pSub->pOrderBy==0 );
108710108900
pSub->pOrderBy = p->pOrderBy;
108711108901
p->pOrderBy = 0;
108712108902
}
@@ -108714,17 +108904,20 @@
108714108904
/* Recursively resolve names in all subqueries in the FROM clause
108715108905
*/
108716108906
if( pOuterNC ) pOuterNC->nNestedSelect++;
108717108907
for(i=0; i<p->pSrc->nSrc; i++){
108718108908
SrcItem *pItem = &p->pSrc->a[i];
108719
- assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/
108720
- if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
108909
+ assert( pItem->zName!=0
108910
+ || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
108911
+ if( pItem->fg.isSubquery
108912
+ && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
108913
+ ){
108721108914
int nRef = pOuterNC ? pOuterNC->nRef : 0;
108722108915
const char *zSavedContext = pParse->zAuthContext;
108723108916
108724108917
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
108725
- sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
108918
+ sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
108726108919
pParse->zAuthContext = zSavedContext;
108727108920
if( pParse->nErr ) return WRC_Abort;
108728108921
assert( db->mallocFailed==0 );
108729108922
108730108923
/* If the number of references to the outer context changed when
@@ -108822,11 +109015,14 @@
108822109015
** the sub-query back to the parent query. At this point each term
108823109016
** within the ORDER BY clause has been transformed to an integer value.
108824109017
** These integers will be replaced by copies of the corresponding result
108825109018
** set expressions by the call to resolveOrderGroupBy() below. */
108826109019
if( p->selFlags & SF_Converted ){
108827
- Select *pSub = p->pSrc->a[0].pSelect;
109020
+ Select *pSub;
109021
+ assert( p->pSrc->a[0].fg.isSubquery );
109022
+ pSub = p->pSrc->a[0].u4.pSubq->pSelect;
109023
+ assert( pSub!=0 );
108828109024
p->pOrderBy = pSub->pOrderBy;
108829109025
pSub->pOrderBy = 0;
108830109026
}
108831109027
108832109028
/* Process the ORDER BY clause for singleton SELECT statements.
@@ -109089,11 +109285,11 @@
109089109285
memset(&sNC, 0, sizeof(sNC));
109090109286
memset(&sSrc, 0, sizeof(sSrc));
109091109287
if( pTab ){
109092109288
sSrc.nSrc = 1;
109093109289
sSrc.a[0].zName = pTab->zName;
109094
- sSrc.a[0].pTab = pTab;
109290
+ sSrc.a[0].pSTab = pTab;
109095109291
sSrc.a[0].iCursor = -1;
109096109292
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
109097109293
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
109098109294
** schema elements */
109099109295
type |= NC_FromDDL;
@@ -110986,19 +111182,34 @@
110986111182
pNew->nSrc = pNew->nAlloc = p->nSrc;
110987111183
for(i=0; i<p->nSrc; i++){
110988111184
SrcItem *pNewItem = &pNew->a[i];
110989111185
const SrcItem *pOldItem = &p->a[i];
110990111186
Table *pTab;
110991
- pNewItem->pSchema = pOldItem->pSchema;
110992
- pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
111187
+ pNewItem->fg = pOldItem->fg;
111188
+ if( pOldItem->fg.isSubquery ){
111189
+ Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery));
111190
+ if( pNewSubq==0 ){
111191
+ assert( db->mallocFailed );
111192
+ pNewItem->fg.isSubquery = 0;
111193
+ }else{
111194
+ memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
111195
+ pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags);
111196
+ if( pNewSubq->pSelect==0 ){
111197
+ sqlite3DbFree(db, pNewSubq);
111198
+ pNewSubq = 0;
111199
+ pNewItem->fg.isSubquery = 0;
111200
+ }
111201
+ }
111202
+ pNewItem->u4.pSubq = pNewSubq;
111203
+ }else if( pOldItem->fg.fixedSchema ){
111204
+ pNewItem->u4.pSchema = pOldItem->u4.pSchema;
111205
+ }else{
111206
+ pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
111207
+ }
110993111208
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
110994111209
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
110995
- pNewItem->fg = pOldItem->fg;
110996111210
pNewItem->iCursor = pOldItem->iCursor;
110997
- pNewItem->addrFillSub = pOldItem->addrFillSub;
110998
- pNewItem->regReturn = pOldItem->regReturn;
110999
- pNewItem->regResult = pOldItem->regResult;
111000111211
if( pNewItem->fg.isIndexedBy ){
111001111212
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
111002111213
}else if( pNewItem->fg.isTabFunc ){
111003111214
pNewItem->u1.pFuncArg =
111004111215
sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
@@ -111007,15 +111218,14 @@
111007111218
}
111008111219
pNewItem->u2 = pOldItem->u2;
111009111220
if( pNewItem->fg.isCte ){
111010111221
pNewItem->u2.pCteUse->nUse++;
111011111222
}
111012
- pTab = pNewItem->pTab = pOldItem->pTab;
111223
+ pTab = pNewItem->pSTab = pOldItem->pSTab;
111013111224
if( pTab ){
111014111225
pTab->nTabRef++;
111015111226
}
111016
- pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
111017111227
if( pOldItem->fg.isUsing ){
111018111228
assert( pNewItem->fg.isUsing );
111019111229
pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
111020111230
}else{
111021111231
pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
@@ -111085,11 +111295,10 @@
111085111295
}
111086111296
*pp = pNew;
111087111297
pp = &pNew->pPrior;
111088111298
pNext = pNew;
111089111299
}
111090
-
111091111300
return pRet;
111092111301
}
111093111302
#else
111094111303
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){
111095111304
assert( p==0 );
@@ -112105,12 +112314,12 @@
112105112314
if( p->pLimit ) return 0; /* Has no LIMIT clause */
112106112315
if( p->pWhere ) return 0; /* Has no WHERE clause */
112107112316
pSrc = p->pSrc;
112108112317
assert( pSrc!=0 );
112109112318
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
112110
- if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
112111
- pTab = pSrc->a[0].pTab;
112319
+ if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
112320
+ pTab = pSrc->a[0].pSTab;
112112112321
assert( pTab!=0 );
112113112322
assert( !IsView(pTab) ); /* FROM clause is not a view */
112114112323
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
112115112324
pEList = p->pEList;
112116112325
assert( pEList!=0 );
@@ -112289,11 +112498,11 @@
112289112498
int nExpr = pEList->nExpr;
112290112499
112291112500
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
112292112501
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
112293112502
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
112294
- pTab = p->pSrc->a[0].pTab;
112503
+ pTab = p->pSrc->a[0].pSTab;
112295112504
112296112505
/* Code an OP_Transaction and OP_TableLock for <table>. */
112297112506
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
112298112507
assert( iDb>=0 && iDb<SQLITE_MAX_DB );
112299112508
sqlite3CodeVerifySchema(pParse, iDb);
@@ -117727,12 +117936,13 @@
117727117936
}
117728117937
if( pStep->pFrom ){
117729117938
int i;
117730117939
for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
117731117940
SrcItem *p = &pStep->pFrom->a[i];
117732
- if( p->pSelect ){
117733
- sqlite3SelectPrep(pParse, p->pSelect, 0);
117941
+ if( p->fg.isSubquery ){
117942
+ assert( p->u4.pSubq!=0 );
117943
+ sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
117734117944
}
117735117945
}
117736117946
}
117737117947
117738117948
if( db->mallocFailed ){
@@ -117796,12 +118006,16 @@
117796118006
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
117797118007
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
117798118008
}
117799118009
if( pStep->pFrom ){
117800118010
int i;
117801
- for(i=0; i<pStep->pFrom->nSrc; i++){
117802
- sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
118011
+ SrcList *pFrom = pStep->pFrom;
118012
+ for(i=0; i<pFrom->nSrc; i++){
118013
+ if( pFrom->a[i].fg.isSubquery ){
118014
+ assert( pFrom->a[i].u4.pSubq!=0 );
118015
+ sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
118016
+ }
117803118017
}
117804118018
}
117805118019
}
117806118020
}
117807118021
@@ -118044,11 +118258,11 @@
118044118258
assert( pWalker->pParse->db->mallocFailed );
118045118259
return WRC_Abort;
118046118260
}
118047118261
for(i=0; i<pSrc->nSrc; i++){
118048118262
SrcItem *pItem = &pSrc->a[i];
118049
- if( pItem->pTab==p->pTab ){
118263
+ if( pItem->pSTab==p->pTab ){
118050118264
renameTokenFind(pWalker->pParse, p, pItem->zName);
118051118265
}
118052118266
}
118053118267
renameWalkWith(pWalker, pSelect);
118054118268
@@ -121178,24 +121392,25 @@
121178121392
int iDb = sqlite3FindDbName(db, pFix->zDb);
121179121393
SrcList *pList = pSelect->pSrc;
121180121394
121181121395
if( NEVER(pList==0) ) return WRC_Continue;
121182121396
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
121183
- if( pFix->bTemp==0 ){
121184
- if( pItem->zDatabase ){
121185
- if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
121397
+ if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
121398
+ if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
121399
+ if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){
121186121400
sqlite3ErrorMsg(pFix->pParse,
121187121401
"%s %T cannot reference objects in database %s",
121188
- pFix->zType, pFix->pName, pItem->zDatabase);
121402
+ pFix->zType, pFix->pName, pItem->u4.zDatabase);
121189121403
return WRC_Abort;
121190121404
}
121191
- sqlite3DbFree(db, pItem->zDatabase);
121192
- pItem->zDatabase = 0;
121405
+ sqlite3DbFree(db, pItem->u4.zDatabase);
121193121406
pItem->fg.notCte = 1;
121407
+ pItem->fg.hadSchema = 1;
121194121408
}
121195
- pItem->pSchema = pFix->pSchema;
121409
+ pItem->u4.pSchema = pFix->pSchema;
121196121410
pItem->fg.fromDDL = 1;
121411
+ pItem->fg.fixedSchema = 1;
121197121412
}
121198121413
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
121199121414
if( pList->a[i].fg.isUsing==0
121200121415
&& sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
121201121416
){
@@ -121484,11 +121699,11 @@
121484121699
pTab = pParse->pTriggerTab;
121485121700
}else{
121486121701
assert( pTabList );
121487121702
for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
121488121703
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
121489
- pTab = pTabList->a[iSrc].pTab;
121704
+ pTab = pTabList->a[iSrc].pSTab;
121490121705
break;
121491121706
}
121492121707
}
121493121708
}
121494121709
iCol = pExpr->iColumn;
@@ -122087,16 +122302,16 @@
122087122302
Parse *pParse,
122088122303
u32 flags,
122089122304
SrcItem *p
122090122305
){
122091122306
const char *zDb;
122092
- assert( p->pSchema==0 || p->zDatabase==0 );
122093
- if( p->pSchema ){
122094
- int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
122307
+ if( p->fg.fixedSchema ){
122308
+ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
122095122309
zDb = pParse->db->aDb[iDb].zDbSName;
122096122310
}else{
122097
- zDb = p->zDatabase;
122311
+ assert( !p->fg.isSubquery );
122312
+ zDb = p->u4.zDatabase;
122098122313
}
122099122314
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
122100122315
}
122101122316
122102122317
/*
@@ -125077,19 +125292,21 @@
125077125292
if( db->mallocFailed ){
125078125293
goto exit_drop_table;
125079125294
}
125080125295
assert( pParse->nErr==0 );
125081125296
assert( pName->nSrc==1 );
125297
+ assert( pName->a[0].fg.fixedSchema==0 );
125298
+ assert( pName->a[0].fg.isSubquery==0 );
125082125299
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
125083125300
if( noErr ) db->suppressErr++;
125084125301
assert( isView==0 || isView==LOCATE_VIEW );
125085125302
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
125086125303
if( noErr ) db->suppressErr--;
125087125304
125088125305
if( pTab==0 ){
125089125306
if( noErr ){
125090
- sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
125307
+ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
125091125308
sqlite3ForceNotReadOnly(pParse);
125092125309
}
125093125310
goto exit_drop_table;
125094125311
}
125095125312
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -126176,19 +126393,21 @@
126176126393
if( db->mallocFailed ){
126177126394
goto exit_drop_index;
126178126395
}
126179126396
assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
126180126397
assert( pName->nSrc==1 );
126398
+ assert( pName->a[0].fg.fixedSchema==0 );
126399
+ assert( pName->a[0].fg.isSubquery==0 );
126181126400
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
126182126401
goto exit_drop_index;
126183126402
}
126184
- pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
126403
+ pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
126185126404
if( pIndex==0 ){
126186126405
if( !ifExists ){
126187126406
sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
126188126407
}else{
126189
- sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
126408
+ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
126190126409
sqlite3ForceNotReadOnly(pParse);
126191126410
}
126192126411
pParse->checkSchema = 1;
126193126412
goto exit_drop_index;
126194126413
}
@@ -126481,16 +126700,18 @@
126481126700
}
126482126701
pItem = &pList->a[pList->nSrc-1];
126483126702
if( pDatabase && pDatabase->z==0 ){
126484126703
pDatabase = 0;
126485126704
}
126705
+ assert( pItem->fg.fixedSchema==0 );
126706
+ assert( pItem->fg.isSubquery==0 );
126486126707
if( pDatabase ){
126487126708
pItem->zName = sqlite3NameFromToken(db, pDatabase);
126488
- pItem->zDatabase = sqlite3NameFromToken(db, pTable);
126709
+ pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable);
126489126710
}else{
126490126711
pItem->zName = sqlite3NameFromToken(db, pTable);
126491
- pItem->zDatabase = 0;
126712
+ pItem->u4.zDatabase = 0;
126492126713
}
126493126714
return pList;
126494126715
}
126495126716
126496126717
/*
@@ -126502,16 +126723,43 @@
126502126723
assert( pList || pParse->db->mallocFailed );
126503126724
if( ALWAYS(pList) ){
126504126725
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
126505126726
if( pItem->iCursor>=0 ) continue;
126506126727
pItem->iCursor = pParse->nTab++;
126507
- if( pItem->pSelect ){
126508
- sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
126728
+ if( pItem->fg.isSubquery ){
126729
+ assert( pItem->u4.pSubq!=0 );
126730
+ assert( pItem->u4.pSubq->pSelect!=0 );
126731
+ assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
126732
+ sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
126509126733
}
126510126734
}
126511126735
}
126512126736
}
126737
+
126738
+/*
126739
+** Delete a Subquery object and its substructure.
126740
+*/
126741
+SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){
126742
+ assert( pSubq!=0 && pSubq->pSelect!=0 );
126743
+ sqlite3SelectDelete(db, pSubq->pSelect);
126744
+ sqlite3DbFree(db, pSubq);
126745
+}
126746
+
126747
+/*
126748
+** Remove a Subquery from a SrcItem. Return the associated Select object.
126749
+** The returned Select becomes the responsibility of the caller.
126750
+*/
126751
+SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){
126752
+ Select *pSel;
126753
+ assert( pItem!=0 );
126754
+ assert( pItem->fg.isSubquery );
126755
+ pSel = pItem->u4.pSubq->pSelect;
126756
+ sqlite3DbFree(db, pItem->u4.pSubq);
126757
+ pItem->u4.pSubq = 0;
126758
+ pItem->fg.isSubquery = 0;
126759
+ return pSel;
126760
+}
126513126761
126514126762
/*
126515126763
** Delete an entire SrcList including all its substructure.
126516126764
*/
126517126765
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
@@ -126518,25 +126766,84 @@
126518126766
int i;
126519126767
SrcItem *pItem;
126520126768
assert( db!=0 );
126521126769
if( pList==0 ) return;
126522126770
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
126523
- if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
126771
+
126772
+ /* Check invariants on SrcItem */
126773
+ assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
126774
+ assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
126775
+ assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
126776
+ assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
126777
+ pItem->u4.pSubq->pSelect!=0) );
126778
+
126524126779
if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
126525126780
if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
126781
+ if( pItem->fg.isSubquery ){
126782
+ sqlite3SubqueryDelete(db, pItem->u4.pSubq);
126783
+ }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
126784
+ sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
126785
+ }
126526126786
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
126527126787
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
126528
- sqlite3DeleteTable(db, pItem->pTab);
126529
- if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
126788
+ sqlite3DeleteTable(db, pItem->pSTab);
126530126789
if( pItem->fg.isUsing ){
126531126790
sqlite3IdListDelete(db, pItem->u3.pUsing);
126532126791
}else if( pItem->u3.pOn ){
126533126792
sqlite3ExprDelete(db, pItem->u3.pOn);
126534126793
}
126535126794
}
126536126795
sqlite3DbNNFreeNN(db, pList);
126537126796
}
126797
+
126798
+/*
126799
+** Attach a Subquery object to pItem->uv.pSubq. Set the
126800
+** pSelect value but leave all the other values initialized
126801
+** to zero.
126802
+**
126803
+** A copy of the Select object is made if dupSelect is true, and the
126804
+** SrcItem takes responsibility for deleting the copy. If dupSelect is
126805
+** false, ownership of the Select passes to the SrcItem. Either way,
126806
+** the SrcItem will take responsibility for deleting the Select.
126807
+**
126808
+** When dupSelect is zero, that means the Select might get deleted right
126809
+** away if there is an OOM error. Beware.
126810
+**
126811
+** Return non-zero on success. Return zero on an OOM error.
126812
+*/
126813
+SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(
126814
+ Parse *pParse, /* Parsing context */
126815
+ SrcItem *pItem, /* Item to which the subquery is to be attached */
126816
+ Select *pSelect, /* The subquery SELECT. Must be non-NULL */
126817
+ int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
126818
+){
126819
+ Subquery *p;
126820
+ assert( pSelect!=0 );
126821
+ assert( pItem->fg.isSubquery==0 );
126822
+ if( pItem->fg.fixedSchema ){
126823
+ pItem->u4.pSchema = 0;
126824
+ pItem->fg.fixedSchema = 0;
126825
+ }else if( pItem->u4.zDatabase!=0 ){
126826
+ sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
126827
+ pItem->u4.zDatabase = 0;
126828
+ }
126829
+ if( dupSelect ){
126830
+ pSelect = sqlite3SelectDup(pParse->db, pSelect, 0);
126831
+ if( pSelect==0 ) return 0;
126832
+ }
126833
+ p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
126834
+ if( p==0 ){
126835
+ sqlite3SelectDelete(pParse->db, pSelect);
126836
+ return 0;
126837
+ }
126838
+ pItem->fg.isSubquery = 1;
126839
+ p->pSelect = pSelect;
126840
+ assert( offsetof(Subquery, pSelect)==0 );
126841
+ memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
126842
+ return 1;
126843
+}
126844
+
126538126845
126539126846
/*
126540126847
** This routine is called by the parser to add a new term to the
126541126848
** end of a growing FROM clause. The "p" parameter is the part of
126542126849
** the FROM clause that has already been constructed. "p" is NULL
@@ -126583,14 +126890,16 @@
126583126890
}
126584126891
assert( pAlias!=0 );
126585126892
if( pAlias->n ){
126586126893
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
126587126894
}
126895
+ assert( pSubquery==0 || pDatabase==0 );
126588126896
if( pSubquery ){
126589
- pItem->pSelect = pSubquery;
126590
- if( pSubquery->selFlags & SF_NestedFrom ){
126591
- pItem->fg.isNestedFrom = 1;
126897
+ if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
126898
+ if( pSubquery->selFlags & SF_NestedFrom ){
126899
+ pItem->fg.isNestedFrom = 1;
126900
+ }
126592126901
}
126593126902
}
126594126903
assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
126595126904
assert( pItem->fg.isUsing==0 );
126596126905
if( pOnUsing==0 ){
@@ -127864,21 +128173,21 @@
127864128173
** return a pointer. Set an error message and return NULL if the table
127865128174
** name is not found or if any other error occurs.
127866128175
**
127867128176
** The following fields are initialized appropriate in pSrc:
127868128177
**
127869
-** pSrc->a[0].pTab Pointer to the Table object
127870
-** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
128178
+** pSrc->a[0].spTab Pointer to the Table object
128179
+** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
127871128180
**
127872128181
*/
127873128182
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
127874128183
SrcItem *pItem = pSrc->a;
127875128184
Table *pTab;
127876128185
assert( pItem && pSrc->nSrc>=1 );
127877128186
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
127878
- if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
127879
- pItem->pTab = pTab;
128187
+ if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab);
128188
+ pItem->pSTab = pTab;
127880128189
pItem->fg.notCte = 1;
127881128190
if( pTab ){
127882128191
pTab->nTabRef++;
127883128192
if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
127884128193
pTab = 0;
@@ -127996,11 +128305,12 @@
127996128305
pWhere = sqlite3ExprDup(db, pWhere, 0);
127997128306
pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0);
127998128307
if( pFrom ){
127999128308
assert( pFrom->nSrc==1 );
128000128309
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
128001
- pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
128310
+ assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
128311
+ pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
128002128312
assert( pFrom->a[0].fg.isUsing==0 );
128003128313
assert( pFrom->a[0].u3.pOn==0 );
128004128314
}
128005128315
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
128006128316
SF_IncludeHidden, pLimit);
@@ -128058,11 +128368,11 @@
128058128368
** DELETE FROM table_a WHERE rowid IN (
128059128369
** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
128060128370
** );
128061128371
*/
128062128372
128063
- pTab = pSrc->a[0].pTab;
128373
+ pTab = pSrc->a[0].pSTab;
128064128374
if( HasRowid(pTab) ){
128065128375
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
128066128376
pEList = sqlite3ExprListAppend(
128067128377
pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
128068128378
);
@@ -128091,13 +128401,13 @@
128091128401
}
128092128402
}
128093128403
128094128404
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
128095128405
** and the SELECT subtree. */
128096
- pSrc->a[0].pTab = 0;
128406
+ pSrc->a[0].pSTab = 0;
128097128407
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
128098
- pSrc->a[0].pTab = pTab;
128408
+ pSrc->a[0].pSTab = pTab;
128099128409
if( pSrc->a[0].fg.isIndexedBy ){
128100128410
assert( pSrc->a[0].fg.isCte==0 );
128101128411
pSrc->a[0].u2.pIBIndex = 0;
128102128412
pSrc->a[0].fg.isIndexedBy = 0;
128103128413
sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
@@ -130920,11 +131230,15 @@
130920131230
130921131231
/*
130922131232
** group_concat(EXPR, ?SEPARATOR?)
130923131233
** string_agg(EXPR, SEPARATOR)
130924131234
**
130925
-** The SEPARATOR goes before the EXPR string. This is tragic. The
131235
+** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
131236
+** coming before the EXPR value, except for the first entry which
131237
+** omits the SEPARATOR.
131238
+**
131239
+** It is tragic that the SEPARATOR goes before the EXPR string. The
130926131240
** groupConcatInverse() implementation would have been easier if the
130927131241
** SEPARATOR were appended after EXPR. And the order is undocumented,
130928131242
** so we could change it, in theory. But the old behavior has been
130929131243
** around for so long that we dare not, for fear of breaking something.
130930131244
*/
@@ -131024,11 +131338,11 @@
131024131338
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
131025131339
pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
131026131340
/* pGCC is always non-NULL since groupConcatStep() will have always
131027131341
** run first to initialize it */
131028131342
if( ALWAYS(pGCC) ){
131029
- int nVS;
131343
+ int nVS; /* Number of characters to remove */
131030131344
/* Must call sqlite3_value_text() to convert the argument into text prior
131031131345
** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
131032131346
(void)sqlite3_value_text(argv[0]);
131033131347
nVS = sqlite3_value_bytes(argv[0]);
131034131348
pGCC->nAccum -= 1;
@@ -132675,13 +132989,13 @@
132675132989
/* Create a SrcList structure containing the child table. We need the
132676132990
** child table as a SrcList for sqlite3WhereBegin() */
132677132991
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
132678132992
if( pSrc ){
132679132993
SrcItem *pItem = pSrc->a;
132680
- pItem->pTab = pFKey->pFrom;
132994
+ pItem->pSTab = pFKey->pFrom;
132681132995
pItem->zName = pFKey->pFrom->zName;
132682
- pItem->pTab->nTabRef++;
132996
+ pItem->pSTab->nTabRef++;
132683132997
pItem->iCursor = pParse->nTab++;
132684132998
132685132999
if( regNew!=0 ){
132686133000
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
132687133001
}
@@ -132969,11 +133283,12 @@
132969133283
}
132970133284
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
132971133285
if( pSrc ){
132972133286
assert( pSrc->nSrc==1 );
132973133287
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
132974
- pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
133288
+ assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
133289
+ pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
132975133290
}
132976133291
pSelect = sqlite3SelectNew(pParse,
132977133292
sqlite3ExprListAppend(pParse, 0, pRaise),
132978133293
pSrc,
132979133294
pWhere,
@@ -133703,12 +134018,15 @@
133703134018
** co-routine.
133704134019
*/
133705134020
SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
133706134021
if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
133707134022
SrcItem *pItem = &pVal->pSrc->a[0];
133708
- sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
133709
- sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
134023
+ assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
134024
+ if( pItem->fg.isSubquery ){
134025
+ sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
134026
+ sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
134027
+ }
133710134028
}
133711134029
}
133712134030
133713134031
/*
133714134032
** Return true if all expressions in the expression-list passed as the
@@ -133832,56 +134150,67 @@
133832134150
sqlite3ReadSchema(pParse);
133833134151
}
133834134152
133835134153
if( pRet ){
133836134154
SelectDest dest;
134155
+ Subquery *pSubq;
133837134156
pRet->pSrc->nSrc = 1;
133838134157
pRet->pPrior = pLeft->pPrior;
133839134158
pRet->op = pLeft->op;
133840134159
if( pRet->pPrior ) pRet->selFlags |= SF_Values;
133841134160
pLeft->pPrior = 0;
133842134161
pLeft->op = TK_SELECT;
133843134162
assert( pLeft->pNext==0 );
133844134163
assert( pRet->pNext==0 );
133845134164
p = &pRet->pSrc->a[0];
133846
- p->pSelect = pLeft;
133847134165
p->fg.viaCoroutine = 1;
133848
- p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
133849
- p->regReturn = ++pParse->nMem;
133850134166
p->iCursor = -1;
134167
+ assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
133851134168
p->u1.nRow = 2;
133852
- sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
133853
- sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
133854
-
133855
- /* Allocate registers for the output of the co-routine. Do so so
133856
- ** that there are two unused registers immediately before those
133857
- ** used by the co-routine. This allows the code in sqlite3Insert()
133858
- ** to use these registers directly, instead of copying the output
133859
- ** of the co-routine to a separate array for processing. */
133860
- dest.iSdst = pParse->nMem + 3;
133861
- dest.nSdst = pLeft->pEList->nExpr;
133862
- pParse->nMem += 2 + dest.nSdst;
133863
-
133864
- pLeft->selFlags |= SF_MultiValue;
133865
- sqlite3Select(pParse, pLeft, &dest);
133866
- p->regResult = dest.iSdst;
133867
- assert( pParse->nErr || dest.iSdst>0 );
134169
+ if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
134170
+ pSubq = p->u4.pSubq;
134171
+ pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
134172
+ pSubq->regReturn = ++pParse->nMem;
134173
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine,
134174
+ pSubq->regReturn, 0, pSubq->addrFillSub);
134175
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
134176
+
134177
+ /* Allocate registers for the output of the co-routine. Do so so
134178
+ ** that there are two unused registers immediately before those
134179
+ ** used by the co-routine. This allows the code in sqlite3Insert()
134180
+ ** to use these registers directly, instead of copying the output
134181
+ ** of the co-routine to a separate array for processing. */
134182
+ dest.iSdst = pParse->nMem + 3;
134183
+ dest.nSdst = pLeft->pEList->nExpr;
134184
+ pParse->nMem += 2 + dest.nSdst;
134185
+
134186
+ pLeft->selFlags |= SF_MultiValue;
134187
+ sqlite3Select(pParse, pLeft, &dest);
134188
+ pSubq->regResult = dest.iSdst;
134189
+ assert( pParse->nErr || dest.iSdst>0 );
134190
+ }
133868134191
pLeft = pRet;
133869134192
}
133870134193
}else{
133871134194
p = &pLeft->pSrc->a[0];
133872134195
assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
133873134196
p->u1.nRow++;
133874134197
}
133875134198
133876134199
if( pParse->nErr==0 ){
134200
+ Subquery *pSubq;
133877134201
assert( p!=0 );
133878
- if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
133879
- sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
134202
+ assert( p->fg.isSubquery );
134203
+ pSubq = p->u4.pSubq;
134204
+ assert( pSubq!=0 );
134205
+ assert( pSubq->pSelect!=0 );
134206
+ assert( pSubq->pSelect->pEList!=0 );
134207
+ if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
134208
+ sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
133880134209
}else{
133881
- sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
133882
- sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
134210
+ sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
134211
+ sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
133883134212
}
133884134213
}
133885134214
sqlite3ExprListDelete(pParse->db, pRow);
133886134215
}
133887134216
@@ -134228,13 +134557,18 @@
134228134557
if( pSelect->pSrc->nSrc==1
134229134558
&& pSelect->pSrc->a[0].fg.viaCoroutine
134230134559
&& pSelect->pPrior==0
134231134560
){
134232134561
SrcItem *pItem = &pSelect->pSrc->a[0];
134233
- dest.iSDParm = pItem->regReturn;
134234
- regFromSelect = pItem->regResult;
134235
- nColumn = pItem->pSelect->pEList->nExpr;
134562
+ Subquery *pSubq;
134563
+ assert( pItem->fg.isSubquery );
134564
+ pSubq = pItem->u4.pSubq;
134565
+ dest.iSDParm = pSubq->regReturn;
134566
+ regFromSelect = pSubq->regResult;
134567
+ assert( pSubq->pSelect!=0 );
134568
+ assert( pSubq->pSelect->pEList!=0 );
134569
+ nColumn = pSubq->pSelect->pEList->nExpr;
134236134570
ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
134237134571
if( bIdListInOrder && nColumn==pTab->nCol ){
134238134572
regData = regFromSelect;
134239134573
regRowid = regData - 1;
134240134574
regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
@@ -136150,11 +136484,11 @@
136150136484
}
136151136485
assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
136152136486
if( pSelect->pSrc->nSrc!=1 ){
136153136487
return 0; /* FROM clause must have exactly one term */
136154136488
}
136155
- if( pSelect->pSrc->a[0].pSelect ){
136489
+ if( pSelect->pSrc->a[0].fg.isSubquery ){
136156136490
return 0; /* FROM clause cannot contain a subquery */
136157136491
}
136158136492
if( pSelect->pWhere ){
136159136493
return 0; /* SELECT may not have a WHERE clause */
136160136494
}
@@ -143448,15 +143782,17 @@
143448143782
/*
143449143783
** Mark a subquery result column as having been used.
143450143784
*/
143451143785
SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
143452143786
assert( pItem!=0 );
143453
- assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
143787
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
143454143788
if( pItem->fg.isNestedFrom ){
143455143789
ExprList *pResults;
143456
- assert( pItem->pSelect!=0 );
143457
- pResults = pItem->pSelect->pEList;
143790
+ assert( pItem->fg.isSubquery );
143791
+ assert( pItem->u4.pSubq!=0 );
143792
+ assert( pItem->u4.pSubq->pSelect!=0 );
143793
+ pResults = pItem->u4.pSubq->pSelect->pEList;
143458143794
assert( pResults!=0 );
143459143795
assert( iCol>=0 && iCol<pResults->nExpr );
143460143796
pResults->a[iCol].fg.bUsed = 1;
143461143797
}
143462143798
}
@@ -143486,13 +143822,13 @@
143486143822
assert( iEnd<pSrc->nSrc );
143487143823
assert( iStart>=0 );
143488143824
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
143489143825
143490143826
for(i=iStart; i<=iEnd; i++){
143491
- iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
143827
+ iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
143492143828
if( iCol>=0
143493
- && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
143829
+ && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
143494143830
){
143495143831
if( piTab ){
143496143832
sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
143497143833
*piTab = i;
143498143834
*piCol = iCol;
@@ -143617,14 +143953,14 @@
143617143953
143618143954
pSrc = p->pSrc;
143619143955
pLeft = &pSrc->a[0];
143620143956
pRight = &pLeft[1];
143621143957
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
143622
- Table *pRightTab = pRight->pTab;
143958
+ Table *pRightTab = pRight->pSTab;
143623143959
u32 joinType;
143624143960
143625
- if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
143961
+ if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
143626143962
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
143627143963
143628143964
/* If this is a NATURAL join, synthesize an appropriate USING clause
143629143965
** to specify which columns should be joined.
143630143966
*/
@@ -145046,12 +145382,16 @@
145046145382
int iCol = pExpr->iColumn; /* Index of column in pTab */
145047145383
while( pNC && !pTab ){
145048145384
SrcList *pTabList = pNC->pSrcList;
145049145385
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
145050145386
if( j<pTabList->nSrc ){
145051
- pTab = pTabList->a[j].pTab;
145052
- pS = pTabList->a[j].pSelect;
145387
+ pTab = pTabList->a[j].pSTab;
145388
+ if( pTabList->a[j].fg.isSubquery ){
145389
+ pS = pTabList->a[j].u4.pSubq->pSelect;
145390
+ }else{
145391
+ pS = 0;
145392
+ }
145053145393
}else{
145054145394
pNC = pNC->pNext;
145055145395
}
145056145396
}
145057145397
@@ -147099,11 +147439,13 @@
147099147439
p->pHaving = substExpr(pSubst, p->pHaving);
147100147440
p->pWhere = substExpr(pSubst, p->pWhere);
147101147441
pSrc = p->pSrc;
147102147442
assert( pSrc!=0 );
147103147443
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
147104
- substSelect(pSubst, pItem->pSelect, 1);
147444
+ if( pItem->fg.isSubquery ){
147445
+ substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
147446
+ }
147105147447
if( pItem->fg.isTabFunc ){
147106147448
substExprList(pSubst, pItem->u1.pFuncArg);
147107147449
}
147108147450
}
147109147451
}while( doPrior && (p = p->pPrior)!=0 );
@@ -147130,11 +147472,11 @@
147130147472
static void recomputeColumnsUsed(
147131147473
Select *pSelect, /* The complete SELECT statement */
147132147474
SrcItem *pSrcItem /* Which FROM clause item to recompute */
147133147475
){
147134147476
Walker w;
147135
- if( NEVER(pSrcItem->pTab==0) ) return;
147477
+ if( NEVER(pSrcItem->pSTab==0) ) return;
147136147478
memset(&w, 0, sizeof(w));
147137147479
w.xExprCallback = recomputeColumnsUsedExpr;
147138147480
w.xSelectCallback = sqlite3SelectWalkNoop;
147139147481
w.u.pSrcItem = pSrcItem;
147140147482
pSrcItem->colUsed = 0;
@@ -147170,12 +147512,14 @@
147170147512
assert( pItem->iCursor < aCsrMap[0] );
147171147513
if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){
147172147514
aCsrMap[pItem->iCursor+1] = pParse->nTab++;
147173147515
}
147174147516
pItem->iCursor = aCsrMap[pItem->iCursor+1];
147175
- for(p=pItem->pSelect; p; p=p->pPrior){
147176
- srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
147517
+ if( pItem->fg.isSubquery ){
147518
+ for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
147519
+ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
147520
+ }
147177147521
}
147178147522
}
147179147523
}
147180147524
}
147181147525
@@ -147482,11 +147826,12 @@
147482147826
if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
147483147827
pSrc = p->pSrc;
147484147828
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
147485147829
pSubitem = &pSrc->a[iFrom];
147486147830
iParent = pSubitem->iCursor;
147487
- pSub = pSubitem->pSelect;
147831
+ assert( pSubitem->fg.isSubquery );
147832
+ pSub = pSubitem->u4.pSubq->pSelect;
147488147833
assert( pSub!=0 );
147489147834
147490147835
#ifndef SQLITE_OMIT_WINDOWFUNC
147491147836
if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */
147492147837
#endif
@@ -147535,11 +147880,11 @@
147535147880
**
147536147881
** See also tickets #306, #350, and #3300.
147537147882
*/
147538147883
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
147539147884
if( pSubSrc->nSrc>1 /* (3a) */
147540
- || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
147885
+ || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
147541147886
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
147542147887
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
147543147888
){
147544147889
return 0;
147545147890
}
@@ -147621,18 +147966,22 @@
147621147966
TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
147622147967
testcase( i==SQLITE_DENY );
147623147968
pParse->zAuthContext = zSavedAuthContext;
147624147969
147625147970
/* Delete the transient structures associated with the subquery */
147626
- pSub1 = pSubitem->pSelect;
147627
- sqlite3DbFree(db, pSubitem->zDatabase);
147971
+
147972
+ if( ALWAYS(pSubitem->fg.isSubquery) ){
147973
+ pSub1 = sqlite3SubqueryDetach(db, pSubitem);
147974
+ }else{
147975
+ pSub1 = 0;
147976
+ }
147977
+ assert( pSubitem->fg.isSubquery==0 );
147978
+ assert( pSubitem->fg.fixedSchema==0 );
147628147979
sqlite3DbFree(db, pSubitem->zName);
147629147980
sqlite3DbFree(db, pSubitem->zAlias);
147630
- pSubitem->zDatabase = 0;
147631147981
pSubitem->zName = 0;
147632147982
pSubitem->zAlias = 0;
147633
- pSubitem->pSelect = 0;
147634147983
assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
147635147984
147636147985
/* If the sub-query is a compound SELECT statement, then (by restrictions
147637147986
** 17 and 18 above) it must be a UNION ALL and the parent query must
147638147987
** be of the form:
@@ -147669,20 +148018,20 @@
147669148018
for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
147670148019
Select *pNew;
147671148020
ExprList *pOrderBy = p->pOrderBy;
147672148021
Expr *pLimit = p->pLimit;
147673148022
Select *pPrior = p->pPrior;
147674
- Table *pItemTab = pSubitem->pTab;
147675
- pSubitem->pTab = 0;
148023
+ Table *pItemTab = pSubitem->pSTab;
148024
+ pSubitem->pSTab = 0;
147676148025
p->pOrderBy = 0;
147677148026
p->pPrior = 0;
147678148027
p->pLimit = 0;
147679148028
pNew = sqlite3SelectDup(db, p, 0);
147680148029
p->pLimit = pLimit;
147681148030
p->pOrderBy = pOrderBy;
147682148031
p->op = TK_ALL;
147683
- pSubitem->pTab = pItemTab;
148032
+ pSubitem->pSTab = pItemTab;
147684148033
if( pNew==0 ){
147685148034
p->pPrior = pPrior;
147686148035
}else{
147687148036
pNew->selId = ++pParse->nSelect;
147688148037
if( aCsrMap && ALWAYS(db->mallocFailed==0) ){
@@ -147693,15 +148042,18 @@
147693148042
pNew->pNext = p;
147694148043
p->pPrior = pNew;
147695148044
TREETRACE(0x4,pParse,p,("compound-subquery flattener"
147696148045
" creates %u as peer\n",pNew->selId));
147697148046
}
147698
- assert( pSubitem->pSelect==0 );
148047
+ assert( pSubitem->fg.isSubquery==0 );
147699148048
}
147700148049
sqlite3DbFree(db, aCsrMap);
147701148050
if( db->mallocFailed ){
147702
- pSubitem->pSelect = pSub1;
148051
+ assert( pSubitem->fg.fixedSchema==0 );
148052
+ assert( pSubitem->fg.isSubquery==0 );
148053
+ assert( pSubitem->u4.zDatabase==0 );
148054
+ sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
147703148055
return 1;
147704148056
}
147705148057
147706148058
/* Defer deleting the Table object associated with the
147707148059
** subquery until code generation is
@@ -147708,20 +148060,20 @@
147708148060
** complete, since there may still exist Expr.pTab entries that
147709148061
** refer to the subquery even after flattening. Ticket #3346.
147710148062
**
147711148063
** pSubitem->pTab is always non-NULL by test restrictions and tests above.
147712148064
*/
147713
- if( ALWAYS(pSubitem->pTab!=0) ){
147714
- Table *pTabToDel = pSubitem->pTab;
148065
+ if( ALWAYS(pSubitem->pSTab!=0) ){
148066
+ Table *pTabToDel = pSubitem->pSTab;
147715148067
if( pTabToDel->nTabRef==1 ){
147716148068
Parse *pToplevel = sqlite3ParseToplevel(pParse);
147717148069
sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
147718148070
testcase( pToplevel->earlyCleanup );
147719148071
}else{
147720148072
pTabToDel->nTabRef--;
147721148073
}
147722
- pSubitem->pTab = 0;
148074
+ pSubitem->pSTab = 0;
147723148075
}
147724148076
147725148077
/* The following loop runs once for each term in a compound-subquery
147726148078
** flattening (as described above). If we are doing a different kind
147727148079
** of flattening - a flattening other than a compound-subquery flattening -
@@ -147773,12 +148125,15 @@
147773148125
/* Transfer the FROM clause terms from the subquery into the
147774148126
** outer query.
147775148127
*/
147776148128
for(i=0; i<nSubSrc; i++){
147777148129
SrcItem *pItem = &pSrc->a[i+iFrom];
147778
- if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
147779148130
assert( pItem->fg.isTabFunc==0 );
148131
+ assert( pItem->fg.isSubquery
148132
+ || pItem->fg.fixedSchema
148133
+ || pItem->u4.zDatabase==0 );
148134
+ if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
147780148135
*pItem = pSubSrc->a[i];
147781148136
pItem->fg.jointype |= ltorj;
147782148137
iNewParent = pSubSrc->a[i].iCursor;
147783148138
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
147784148139
}
@@ -148458,14 +148813,14 @@
148458148813
148459148814
assert( pItem!=0 );
148460148815
if( pItem->fg.isCorrelated || pItem->fg.isCte ){
148461148816
return 0;
148462148817
}
148463
- assert( pItem->pTab!=0 );
148464
- pTab = pItem->pTab;
148465
- assert( pItem->pSelect!=0 );
148466
- pSub = pItem->pSelect;
148818
+ assert( pItem->pSTab!=0 );
148819
+ pTab = pItem->pSTab;
148820
+ assert( pItem->fg.isSubquery );
148821
+ pSub = pItem->u4.pSubq->pSelect;
148467148822
assert( pSub->pEList->nExpr==pTab->nCol );
148468148823
for(pX=pSub; pX; pX=pX->pPrior){
148469148824
if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
148470148825
testcase( pX->selFlags & SF_Distinct );
148471148826
testcase( pX->selFlags & SF_Aggregate );
@@ -148590,17 +148945,17 @@
148590148945
assert( !p->pGroupBy );
148591148946
148592148947
if( p->pWhere
148593148948
|| p->pEList->nExpr!=1
148594148949
|| p->pSrc->nSrc!=1
148595
- || p->pSrc->a[0].pSelect
148950
+ || p->pSrc->a[0].fg.isSubquery
148596148951
|| pAggInfo->nFunc!=1
148597148952
|| p->pHaving
148598148953
){
148599148954
return 0;
148600148955
}
148601
- pTab = p->pSrc->a[0].pTab;
148956
+ pTab = p->pSrc->a[0].pSTab;
148602148957
assert( pTab!=0 );
148603148958
assert( !IsView(pTab) );
148604148959
if( !IsOrdinaryTable(pTab) ) return 0;
148605148960
pExpr = p->pEList->a[0].pExpr;
148606148961
assert( pExpr!=0 );
@@ -148621,11 +148976,11 @@
148621148976
** was such a clause and the named index cannot be found, return
148622148977
** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
148623148978
** pFrom->pIndex and return SQLITE_OK.
148624148979
*/
148625148980
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
148626
- Table *pTab = pFrom->pTab;
148981
+ Table *pTab = pFrom->pSTab;
148627148982
char *zIndexedBy = pFrom->u1.zIndexedBy;
148628148983
Index *pIdx;
148629148984
assert( pTab!=0 );
148630148985
assert( pFrom->fg.isIndexedBy!=0 );
148631148986
@@ -148698,11 +149053,15 @@
148698149053
db = pParse->db;
148699149054
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
148700149055
if( pNew==0 ) return WRC_Abort;
148701149056
memset(&dummy, 0, sizeof(dummy));
148702149057
pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
148703
- if( pNewSrc==0 ) return WRC_Abort;
149058
+ assert( pNewSrc!=0 || pParse->nErr );
149059
+ if( pParse->nErr ){
149060
+ sqlite3SrcListDelete(db, pNewSrc);
149061
+ return WRC_Abort;
149062
+ }
148704149063
*pNew = *p;
148705149064
p->pSrc = pNewSrc;
148706149065
p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
148707149066
p->op = TK_SELECT;
148708149067
p->pWhere = 0;
@@ -148753,11 +149112,11 @@
148753149112
SrcItem *pItem, /* FROM clause element to resolve */
148754149113
With **ppContext /* OUT: WITH clause return value belongs to */
148755149114
){
148756149115
const char *zName = pItem->zName;
148757149116
With *p;
148758
- assert( pItem->zDatabase==0 );
149117
+ assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
148759149118
assert( zName!=0 );
148760149119
for(p=pWith; p; p=p->pOuter){
148761149120
int i;
148762149121
for(i=0; i<p->nCte; i++){
148763149122
if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
@@ -148823,21 +149182,22 @@
148823149182
SrcItem *pFrom /* The FROM clause term to check */
148824149183
){
148825149184
Cte *pCte; /* Matched CTE (or NULL if no match) */
148826149185
With *pWith; /* The matching WITH */
148827149186
148828
- assert( pFrom->pTab==0 );
149187
+ assert( pFrom->pSTab==0 );
148829149188
if( pParse->pWith==0 ){
148830149189
/* There are no WITH clauses in the stack. No match is possible */
148831149190
return 0;
148832149191
}
148833149192
if( pParse->nErr ){
148834149193
/* Prior errors might have left pParse->pWith in a goofy state, so
148835149194
** go no further. */
148836149195
return 0;
148837149196
}
148838
- if( pFrom->zDatabase!=0 ){
149197
+ assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
149198
+ if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
148839149199
/* The FROM term contains a schema qualifier (ex: main.t1) and so
148840149200
** it cannot possibly be a CTE reference. */
148841149201
return 0;
148842149202
}
148843149203
if( pFrom->fg.notCte ){
@@ -148869,11 +149229,11 @@
148869149229
sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
148870149230
return 2;
148871149231
}
148872149232
if( cannotBeFunction(pParse, pFrom) ) return 2;
148873149233
148874
- assert( pFrom->pTab==0 );
149234
+ assert( pFrom->pSTab==0 );
148875149235
pTab = sqlite3DbMallocZero(db, sizeof(Table));
148876149236
if( pTab==0 ) return 2;
148877149237
pCteUse = pCte->pUse;
148878149238
if( pCteUse==0 ){
148879149239
pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
@@ -148883,42 +149243,47 @@
148883149243
sqlite3DbFree(db, pTab);
148884149244
return 2;
148885149245
}
148886149246
pCteUse->eM10d = pCte->eM10d;
148887149247
}
148888
- pFrom->pTab = pTab;
149248
+ pFrom->pSTab = pTab;
148889149249
pTab->nTabRef = 1;
148890149250
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
148891149251
pTab->iPKey = -1;
148892149252
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
148893149253
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
148894
- pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
149254
+ sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
148895149255
if( db->mallocFailed ) return 2;
148896
- pFrom->pSelect->selFlags |= SF_CopyCte;
148897
- assert( pFrom->pSelect );
149256
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
149257
+ pSel = pFrom->u4.pSubq->pSelect;
149258
+ assert( pSel!=0 );
149259
+ pSel->selFlags |= SF_CopyCte;
148898149260
if( pFrom->fg.isIndexedBy ){
148899149261
sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
148900149262
return 2;
148901149263
}
149264
+ assert( !pFrom->fg.isIndexedBy );
148902149265
pFrom->fg.isCte = 1;
148903149266
pFrom->u2.pCteUse = pCteUse;
148904149267
pCteUse->nUse++;
148905149268
148906149269
/* Check if this is a recursive CTE. */
148907
- pRecTerm = pSel = pFrom->pSelect;
149270
+ pRecTerm = pSel;
148908149271
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
148909149272
while( bMayRecursive && pRecTerm->op==pSel->op ){
148910149273
int i;
148911149274
SrcList *pSrc = pRecTerm->pSrc;
148912149275
assert( pRecTerm->pPrior!=0 );
148913149276
for(i=0; i<pSrc->nSrc; i++){
148914149277
SrcItem *pItem = &pSrc->a[i];
148915
- if( pItem->zDatabase==0
148916
- && pItem->zName!=0
149278
+ if( pItem->zName!=0
149279
+ && !pItem->fg.hadSchema
149280
+ && ALWAYS( !pItem->fg.isSubquery )
149281
+ && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
148917149282
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
148918149283
){
148919
- pItem->pTab = pTab;
149284
+ pItem->pSTab = pTab;
148920149285
pTab->nTabRef++;
148921149286
pItem->fg.isRecursive = 1;
148922149287
if( pRecTerm->selFlags & SF_Recursive ){
148923149288
sqlite3ErrorMsg(pParse,
148924149289
"multiple references to recursive table: %s", pCte->zName
@@ -149016,15 +149381,18 @@
149016149381
** allocates and populates the SrcItem.pTab object. If successful,
149017149382
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
149018149383
** SQLITE_NOMEM.
149019149384
*/
149020149385
SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
149021
- Select *pSel = pFrom->pSelect;
149386
+ Select *pSel;
149022149387
Table *pTab;
149023149388
149389
+ assert( pFrom->fg.isSubquery );
149390
+ assert( pFrom->u4.pSubq!=0 );
149391
+ pSel = pFrom->u4.pSubq->pSelect;
149024149392
assert( pSel );
149025
- pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
149393
+ pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
149026149394
if( pTab==0 ) return SQLITE_NOMEM;
149027149395
pTab->nTabRef = 1;
149028149396
if( pFrom->zAlias ){
149029149397
pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
149030149398
}else{
@@ -149140,37 +149508,39 @@
149140149508
** an entry of the FROM clause is a subquery instead of a table or view,
149141149509
** then create a transient table structure to describe the subquery.
149142149510
*/
149143149511
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149144149512
Table *pTab;
149145
- assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
149146
- if( pFrom->pTab ) continue;
149513
+ assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
149514
+ if( pFrom->pSTab ) continue;
149147149515
assert( pFrom->fg.isRecursive==0 );
149148149516
if( pFrom->zName==0 ){
149149149517
#ifndef SQLITE_OMIT_SUBQUERY
149150
- Select *pSel = pFrom->pSelect;
149518
+ Select *pSel;
149519
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
149520
+ pSel = pFrom->u4.pSubq->pSelect;
149151149521
/* A sub-query in the FROM clause of a SELECT */
149152149522
assert( pSel!=0 );
149153
- assert( pFrom->pTab==0 );
149523
+ assert( pFrom->pSTab==0 );
149154149524
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
149155149525
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
149156149526
#endif
149157149527
#ifndef SQLITE_OMIT_CTE
149158149528
}else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
149159149529
if( rc>1 ) return WRC_Abort;
149160
- pTab = pFrom->pTab;
149530
+ pTab = pFrom->pSTab;
149161149531
assert( pTab!=0 );
149162149532
#endif
149163149533
}else{
149164149534
/* An ordinary table or view name in the FROM clause */
149165
- assert( pFrom->pTab==0 );
149166
- pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
149535
+ assert( pFrom->pSTab==0 );
149536
+ pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
149167149537
if( pTab==0 ) return WRC_Abort;
149168149538
if( pTab->nTabRef>=0xffff ){
149169149539
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
149170149540
pTab->zName);
149171
- pFrom->pTab = 0;
149541
+ pFrom->pSTab = 0;
149172149542
return WRC_Abort;
149173149543
}
149174149544
pTab->nTabRef++;
149175149545
if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
149176149546
return WRC_Abort;
@@ -149178,19 +149548,19 @@
149178149548
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
149179149549
if( !IsOrdinaryTable(pTab) ){
149180149550
i16 nCol;
149181149551
u8 eCodeOrig = pWalker->eCode;
149182149552
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
149183
- assert( pFrom->pSelect==0 );
149553
+ assert( pFrom->fg.isSubquery==0 );
149184149554
if( IsView(pTab) ){
149185149555
if( (db->flags & SQLITE_EnableView)==0
149186149556
&& pTab->pSchema!=db->aDb[1].pSchema
149187149557
){
149188149558
sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
149189149559
pTab->zName);
149190149560
}
149191
- pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
149561
+ sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
149192149562
}
149193149563
#ifndef SQLITE_OMIT_VIRTUALTABLE
149194149564
else if( ALWAYS(IsVirtual(pTab))
149195149565
&& pFrom->fg.fromDDL
149196149566
&& ALWAYS(pTab->u.vtab.p!=0)
@@ -149202,11 +149572,13 @@
149202149572
assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
149203149573
#endif
149204149574
nCol = pTab->nCol;
149205149575
pTab->nCol = -1;
149206149576
pWalker->eCode = 1; /* Turn on Select.selId renumbering */
149207
- sqlite3WalkSelect(pWalker, pFrom->pSelect);
149577
+ if( pFrom->fg.isSubquery ){
149578
+ sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
149579
+ }
149208149580
pWalker->eCode = eCodeOrig;
149209149581
pTab->nCol = nCol;
149210149582
}
149211149583
#endif
149212149584
}
@@ -149289,11 +149661,11 @@
149289149661
assert( ExprUseWOfst(pE) );
149290149662
iErrOfst = pE->w.iOfst;
149291149663
}
149292149664
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149293149665
int nAdd; /* Number of cols including rowid */
149294
- Table *pTab = pFrom->pTab; /* Table for this data source */
149666
+ Table *pTab = pFrom->pSTab; /* Table for this data source */
149295149667
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
149296149668
char *zTabName; /* AS name for this data source */
149297149669
const char *zSchemaName = 0; /* Schema name for this data source */
149298149670
int iDb; /* Schema index for this data src */
149299149671
IdList *pUsing; /* USING clause for pFrom[1] */
@@ -149300,14 +149672,15 @@
149300149672
149301149673
if( (zTabName = pFrom->zAlias)==0 ){
149302149674
zTabName = pTab->zName;
149303149675
}
149304149676
if( db->mallocFailed ) break;
149305
- assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
149677
+ assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
149306149678
if( pFrom->fg.isNestedFrom ){
149307
- assert( pFrom->pSelect!=0 );
149308
- pNestedFrom = pFrom->pSelect->pEList;
149679
+ assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
149680
+ assert( pFrom->u4.pSubq->pSelect!=0 );
149681
+ pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
149309149682
assert( pNestedFrom!=0 );
149310149683
assert( pNestedFrom->nExpr==pTab->nCol );
149311149684
assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
149312149685
}else{
149313149686
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
@@ -149542,18 +149915,16 @@
149542149915
p->selFlags |= SF_HasTypeInfo;
149543149916
pParse = pWalker->pParse;
149544149917
assert( (p->selFlags & SF_Resolved) );
149545149918
pTabList = p->pSrc;
149546149919
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149547
- Table *pTab = pFrom->pTab;
149920
+ Table *pTab = pFrom->pSTab;
149548149921
assert( pTab!=0 );
149549
- if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
149922
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
149550149923
/* A sub-query in the FROM clause of a SELECT */
149551
- Select *pSel = pFrom->pSelect;
149552
- if( pSel ){
149553
- sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
149554
- }
149924
+ Select *pSel = pFrom->u4.pSubq->pSelect;
149925
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
149555149926
}
149556149927
}
149557149928
}
149558149929
#endif
149559149930
@@ -149863,10 +150234,11 @@
149863150234
int i;
149864150235
struct AggInfo_func *pF;
149865150236
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
149866150237
ExprList *pList;
149867150238
assert( ExprUseXList(pF->pFExpr) );
150239
+ if( pParse->nErr ) return;
149868150240
pList = pF->pFExpr->x.pList;
149869150241
if( pF->iOBTab>=0 ){
149870150242
/* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
149871150243
** were stored in emphermal table pF->iOBTab. Here, we extract those
149872150244
** inputs (in ORDER BY order) and make all calls to OP_AggStep
@@ -150072,19 +150444,21 @@
150072150444
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
150073150445
}
150074150446
if( addrNext ){
150075150447
sqlite3VdbeResolveLabel(v, addrNext);
150076150448
}
150449
+ if( pParse->nErr ) return;
150077150450
}
150078150451
if( regHit==0 && pAggInfo->nAccumulator ){
150079150452
regHit = regAcc;
150080150453
}
150081150454
if( regHit ){
150082150455
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
150083150456
}
150084150457
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
150085150458
sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
150459
+ if( pParse->nErr ) return;
150086150460
}
150087150461
150088150462
pAggInfo->directMode = 0;
150089150463
if( addrHitTest ){
150090150464
sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
@@ -150196,29 +150570,32 @@
150196150570
SrcList *pTabList, /* Search for self-joins in this FROM clause */
150197150571
SrcItem *pThis, /* Search for prior reference to this subquery */
150198150572
int iFirst, int iEnd /* Range of FROM-clause entries to search. */
150199150573
){
150200150574
SrcItem *pItem;
150201
- assert( pThis->pSelect!=0 );
150202
- if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
150575
+ Select *pSel;
150576
+ assert( pThis->fg.isSubquery );
150577
+ pSel = pThis->u4.pSubq->pSelect;
150578
+ assert( pSel!=0 );
150579
+ if( pSel->selFlags & SF_PushDown ) return 0;
150203150580
while( iFirst<iEnd ){
150204150581
Select *pS1;
150205150582
pItem = &pTabList->a[iFirst++];
150206
- if( pItem->pSelect==0 ) continue;
150583
+ if( !pItem->fg.isSubquery ) continue;
150207150584
if( pItem->fg.viaCoroutine ) continue;
150208150585
if( pItem->zName==0 ) continue;
150209
- assert( pItem->pTab!=0 );
150210
- assert( pThis->pTab!=0 );
150211
- if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue;
150586
+ assert( pItem->pSTab!=0 );
150587
+ assert( pThis->pSTab!=0 );
150588
+ if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
150212150589
if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
150213
- pS1 = pItem->pSelect;
150214
- if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
150590
+ pS1 = pItem->u4.pSubq->pSelect;
150591
+ if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
150215150592
/* The query flattener left two different CTE tables with identical
150216150593
** names in the same FROM clause. */
150217150594
continue;
150218150595
}
150219
- if( pItem->pSelect->selFlags & SF_PushDown ){
150596
+ if( pS1->selFlags & SF_PushDown ){
150220150597
/* The view was modified by some other optimization such as
150221150598
** pushDownWhereTerms() */
150222150599
continue;
150223150600
}
150224150601
return pItem;
@@ -150258,10 +150635,11 @@
150258150635
static int countOfViewOptimization(Parse *pParse, Select *p){
150259150636
Select *pSub, *pPrior;
150260150637
Expr *pExpr;
150261150638
Expr *pCount;
150262150639
sqlite3 *db;
150640
+ SrcItem *pFrom;
150263150641
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
150264150642
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
150265150643
if( p->pWhere ) return 0;
150266150644
if( p->pHaving ) return 0;
150267150645
if( p->pGroupBy ) return 0;
@@ -150272,30 +150650,30 @@
150272150650
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
150273150651
assert( ExprUseXList(pExpr) );
150274150652
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
150275150653
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
150276150654
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
150277
- pSub = p->pSrc->a[0].pSelect;
150278
- if( pSub==0 ) return 0; /* The FROM is a subquery */
150655
+ pFrom = p->pSrc->a;
150656
+ if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
150657
+ pSub = pFrom->u4.pSubq->pSelect;
150279150658
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
150280150659
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
150281150660
do{
150282150661
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
150283150662
if( pSub->pWhere ) return 0; /* No WHERE clause */
150284150663
if( pSub->pLimit ) return 0; /* No LIMIT clause */
150285150664
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
150286150665
assert( pSub->pHaving==0 ); /* Due to the previous */
150287
- pSub = pSub->pPrior; /* Repeat over compound */
150666
+ pSub = pSub->pPrior; /* Repeat over compound */
150288150667
}while( pSub );
150289150668
150290150669
/* If we reach this point then it is OK to perform the transformation */
150291150670
150292150671
db = pParse->db;
150293150672
pCount = pExpr;
150294150673
pExpr = 0;
150295
- pSub = p->pSrc->a[0].pSelect;
150296
- p->pSrc->a[0].pSelect = 0;
150674
+ pSub = sqlite3SubqueryDetach(db, pFrom);
150297150675
sqlite3SrcListDelete(db, p->pSrc);
150298150676
p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
150299150677
while( pSub ){
150300150678
Expr *pTerm;
150301150679
pPrior = pSub->pPrior;
@@ -150336,16 +150714,16 @@
150336150714
static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
150337150715
int i;
150338150716
for(i=0; i<pSrc->nSrc; i++){
150339150717
SrcItem *p1 = &pSrc->a[i];
150340150718
if( p1==p0 ) continue;
150341
- if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
150719
+ if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
150342150720
return 1;
150343150721
}
150344
- if( p1->pSelect
150345
- && (p1->pSelect->selFlags & SF_NestedFrom)!=0
150346
- && sameSrcAlias(p0, p1->pSelect->pSrc)
150722
+ if( p1->fg.isSubquery
150723
+ && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
150724
+ && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
150347150725
){
150348150726
return 1;
150349150727
}
150350150728
}
150351150729
return 0;
@@ -150406,17 +150784,17 @@
150406150784
while( 1 /*exit-by-break*/ ){
150407150785
if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
150408150786
if( i==0 ) break;
150409150787
i--;
150410150788
pItem--;
150411
- if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
150789
+ if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
150412150790
}
150413150791
return 1;
150414150792
}
150415150793
150416150794
/*
150417
-** Generate code for the SELECT statement given in the p argument.
150795
+** Generate byte-code for the SELECT statement given in the p argument.
150418150796
**
150419150797
** The results are returned according to the SelectDest structure.
150420150798
** See comments in sqliteInt.h for further information.
150421150799
**
150422150800
** This routine returns the number of errors. If any errors are
@@ -150423,10 +150801,44 @@
150423150801
** encountered, then an appropriate error message is left in
150424150802
** pParse->zErrMsg.
150425150803
**
150426150804
** This routine does NOT free the Select structure passed in. The
150427150805
** calling function needs to do that.
150806
+**
150807
+** This is a long function. The following is an outline of the processing
150808
+** steps, with tags referencing various milestones:
150809
+**
150810
+** * Resolve names and similar preparation tag-select-0100
150811
+** * Scan of the FROM clause tag-select-0200
150812
+** + OUTER JOIN strength reduction tag-select-0220
150813
+** + Sub-query ORDER BY removal tag-select-0230
150814
+** + Query flattening tag-select-0240
150815
+** * Separate subroutine for compound-SELECT tag-select-0300
150816
+** * WHERE-clause constant propagation tag-select-0330
150817
+** * Count()-of-VIEW optimization tag-select-0350
150818
+** * Scan of the FROM clause again tag-select-0400
150819
+** + Authorize unreferenced tables tag-select-0410
150820
+** + Predicate push-down optimization tag-select-0420
150821
+** + Omit unused subquery columns optimization tag-select-0440
150822
+** + Generate code to implement subqueries tag-select-0480
150823
+** - Co-routines tag-select-0482
150824
+** - Reuse previously computed CTE tag-select-0484
150825
+** - REuse previously computed VIEW tag-select-0486
150826
+** - Materialize a VIEW or CTE tag-select-0488
150827
+** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500
150828
+** * Set up for ORDER BY tag-select-0600
150829
+** * Create output table tag-select-0630
150830
+** * Prepare registers for LIMIT tag-select-0650
150831
+** * Setup for DISTINCT tag-select-0680
150832
+** * Generate code for non-aggregate and non-GROUP BY tag-select-0700
150833
+** * Generate code for aggregate and/or GROUP BY tag-select-0800
150834
+** + GROUP BY queries tag-select-0810
150835
+** + non-GROUP BY queries tag-select-0820
150836
+** - Special case of count() w/o GROUP BY tag-select-0821
150837
+** - General case of non-GROUP BY aggregates tag-select-0822
150838
+** * Sort results, as needed tag-select-0900
150839
+** * Internal self-checks tag-select-1000
150428150840
*/
150429150841
SQLITE_PRIVATE int sqlite3Select(
150430150842
Parse *pParse, /* The parser context */
150431150843
Select *p, /* The SELECT statement being coded. */
150432150844
SelectDest *pDest /* What to do with the query results */
@@ -150466,10 +150878,11 @@
150466150878
}
150467150879
sqlite3ShowSelect(p);
150468150880
}
150469150881
#endif
150470150882
150883
+ /* tag-select-0100 */
150471150884
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
150472150885
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
150473150886
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
150474150887
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
150475150888
if( IgnorableDistinct(pDest) ){
@@ -150517,11 +150930,11 @@
150517150930
if( p->selFlags & SF_UFSrcCheck ){
150518150931
SrcItem *p0 = &p->pSrc->a[0];
150519150932
if( sameSrcAlias(p0, p->pSrc) ){
150520150933
sqlite3ErrorMsg(pParse,
150521150934
"target object/alias may not appear in FROM clause: %s",
150522
- p0->zAlias ? p0->zAlias : p0->pTab->zName
150935
+ p0->zAlias ? p0->zAlias : p0->pSTab->zName
150523150936
);
150524150937
goto select_end;
150525150938
}
150526150939
150527150940
/* Clear the SF_UFSrcCheck flag. The check has already been performed,
@@ -150552,16 +150965,17 @@
150552150965
memset(&sSort, 0, sizeof(sSort));
150553150966
sSort.pOrderBy = p->pOrderBy;
150554150967
150555150968
/* Try to do various optimizations (flattening subqueries, and strength
150556150969
** reduction of join operators) in the FROM clause up into the main query
150970
+ ** tag-select-0200
150557150971
*/
150558150972
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150559150973
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
150560150974
SrcItem *pItem = &pTabList->a[i];
150561
- Select *pSub = pItem->pSelect;
150562
- Table *pTab = pItem->pTab;
150975
+ Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
150976
+ Table *pTab = pItem->pSTab;
150563150977
150564150978
/* The expander should have already created transient Table objects
150565150979
** even for FROM clause elements such as subqueries that do not correspond
150566150980
** to a real table */
150567150981
assert( pTab!=0 );
@@ -150574,10 +150988,11 @@
150574150988
**
150575150989
** If terms of the i-th table are used in the WHERE clause in such a
150576150990
** way that the i-th table cannot be the NULL row of a join, then
150577150991
** perform the appropriate simplification. This is called
150578150992
** "OUTER JOIN strength reduction" in the SQLite documentation.
150993
+ ** tag-select-0220
150579150994
*/
150580150995
if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
150581150996
&& sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
150582150997
pItem->fg.jointype & JT_LTORJ)
150583150998
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
@@ -150644,11 +151059,12 @@
150644151059
** flattening in that case.
150645151060
*/
150646151061
if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
150647151062
assert( pSub->pGroupBy==0 );
150648151063
150649
- /* If a FROM-clause subquery has an ORDER BY clause that is not
151064
+ /* tag-select-0230:
151065
+ ** If a FROM-clause subquery has an ORDER BY clause that is not
150650151066
** really doing anything, then delete it now so that it does not
150651151067
** interfere with query flattening. See the discussion at
150652151068
** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
150653151069
**
150654151070
** Beware of these cases where the ORDER BY clause may not be safely
@@ -150710,10 +151126,11 @@
150710151126
|| (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0)
150711151127
){
150712151128
continue;
150713151129
}
150714151130
151131
+ /* tag-select-0240 */
150715151132
if( flattenSubquery(pParse, p, i, isAgg) ){
150716151133
if( pParse->nErr ) goto select_end;
150717151134
/* This subquery can be absorbed into its parent. */
150718151135
i = -1;
150719151136
}
@@ -150725,11 +151142,11 @@
150725151142
}
150726151143
#endif
150727151144
150728151145
#ifndef SQLITE_OMIT_COMPOUND_SELECT
150729151146
/* Handle compound SELECT statements using the separate multiSelect()
150730
- ** procedure.
151147
+ ** procedure. tag-select-0300
150731151148
*/
150732151149
if( p->pPrior ){
150733151150
rc = multiSelect(pParse, p, pDest);
150734151151
#if TREETRACE_ENABLED
150735151152
TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
@@ -150741,13 +151158,13 @@
150741151158
return rc;
150742151159
}
150743151160
#endif
150744151161
150745151162
/* Do the WHERE-clause constant propagation optimization if this is
150746
- ** a join. No need to speed time on this operation for non-join queries
151163
+ ** a join. No need to spend time on this operation for non-join queries
150747151164
** as the equivalent optimization will be handled by query planner in
150748
- ** sqlite3WhereBegin().
151165
+ ** sqlite3WhereBegin(). tag-select-0330
150749151166
*/
150750151167
if( p->pWhere!=0
150751151168
&& p->pWhere->op==TK_AND
150752151169
&& OptimizationEnabled(db, SQLITE_PropagateConst)
150753151170
&& propagateConstants(pParse, p)
@@ -150760,31 +151177,38 @@
150760151177
#endif
150761151178
}else{
150762151179
TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
150763151180
}
150764151181
151182
+ /* tag-select-0350 */
150765151183
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
150766151184
&& countOfViewOptimization(pParse, p)
150767151185
){
150768151186
if( db->mallocFailed ) goto select_end;
150769151187
pTabList = p->pSrc;
150770151188
}
150771151189
150772
- /* For each term in the FROM clause, do two things:
150773
- ** (1) Authorized unreferenced tables
150774
- ** (2) Generate code for all sub-queries
151190
+ /* Loop over all terms in the FROM clause and do two things for each term:
151191
+ **
151192
+ ** (1) Authorize unreferenced tables
151193
+ ** (2) Generate code for all sub-queries
151194
+ **
151195
+ ** tag-select-0400
150775151196
*/
150776151197
for(i=0; i<pTabList->nSrc; i++){
150777151198
SrcItem *pItem = &pTabList->a[i];
150778151199
SrcItem *pPrior;
150779151200
SelectDest dest;
151201
+ Subquery *pSubq;
150780151202
Select *pSub;
150781151203
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150782151204
const char *zSavedAuthContext;
150783151205
#endif
150784151206
150785
- /* Issue SQLITE_READ authorizations with a fake column name for any
151207
+ /* Authorized unreferenced tables. tag-select-0410
151208
+ **
151209
+ ** Issue SQLITE_READ authorizations with a fake column name for any
150786151210
** tables that are referenced but from which no values are extracted.
150787151211
** Examples of where these kinds of null SQLITE_READ authorizations
150788151212
** would occur:
150789151213
**
150790151214
** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
@@ -150797,21 +151221,32 @@
150797151221
** which would be unambiguous. But legacy authorization callbacks might
150798151222
** assume the column name is non-NULL and segfault. The use of an empty
150799151223
** string for the fake column name seems safer.
150800151224
*/
150801151225
if( pItem->colUsed==0 && pItem->zName!=0 ){
150802
- sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
151226
+ const char *zDb;
151227
+ if( pItem->fg.fixedSchema ){
151228
+ int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
151229
+ zDb = db->aDb[iDb].zDbSName;
151230
+ }else if( pItem->fg.isSubquery ){
151231
+ zDb = 0;
151232
+ }else{
151233
+ zDb = pItem->u4.zDatabase;
151234
+ }
151235
+ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
150803151236
}
150804151237
150805151238
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150806151239
/* Generate code for all sub-queries in the FROM clause
150807151240
*/
150808
- pSub = pItem->pSelect;
150809
- if( pSub==0 || pItem->addrFillSub!=0 ) continue;
151241
+ if( pItem->fg.isSubquery==0 ) continue;
151242
+ pSubq = pItem->u4.pSubq;
151243
+ assert( pSubq!=0 );
151244
+ pSub = pSubq->pSelect;
150810151245
150811151246
/* The code for a subquery should only be generated once. */
150812
- assert( pItem->addrFillSub==0 );
151247
+ if( pSubq->addrFillSub!=0 ) continue;
150813151248
150814151249
/* Increment Parse.nHeight by the height of the largest expression
150815151250
** tree referred to by this, the parent select. The child select
150816151251
** may contain expression trees of at most
150817151252
** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
@@ -150820,10 +151255,11 @@
150820151255
*/
150821151256
pParse->nHeight += sqlite3SelectExprHeight(p);
150822151257
150823151258
/* Make copies of constant WHERE-clause terms in the outer query down
150824151259
** inside the subquery. This can help the subquery to run more efficiently.
151260
+ ** This is the "predicate push-down optimization". tag-select-0420
150825151261
*/
150826151262
if( OptimizationEnabled(db, SQLITE_PushDown)
150827151263
&& (pItem->fg.isCte==0
150828151264
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
150829151265
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
@@ -150833,17 +151269,18 @@
150833151269
TREETRACE(0x4000,pParse,p,
150834151270
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
150835151271
sqlite3TreeViewSelect(0, p, 0);
150836151272
}
150837151273
#endif
150838
- assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
151274
+ assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
150839151275
}else{
150840151276
TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
150841151277
}
150842151278
150843151279
/* Convert unused result columns of the subquery into simple NULL
150844151280
** expressions, to avoid unneeded searching and computation.
151281
+ ** tag-select-0440
150845151282
*/
150846151283
if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
150847151284
&& disableUnusedSubqueryResultColumns(pItem)
150848151285
){
150849151286
#if TREETRACE_ENABLED
@@ -150857,64 +151294,70 @@
150857151294
}
150858151295
150859151296
zSavedAuthContext = pParse->zAuthContext;
150860151297
pParse->zAuthContext = pItem->zName;
150861151298
150862
- /* Generate code to implement the subquery
151299
+ /* Generate byte-code to implement the subquery tag-select-0480
150863151300
*/
150864151301
if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
150865151302
/* Implement a co-routine that will return a single row of the result
150866
- ** set on each invocation.
151303
+ ** set on each invocation. tag-select-0482
150867151304
*/
150868151305
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
150869151306
150870
- pItem->regReturn = ++pParse->nMem;
150871
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
151307
+ pSubq->regReturn = ++pParse->nMem;
151308
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
150872151309
VdbeComment((v, "%!S", pItem));
150873
- pItem->addrFillSub = addrTop;
150874
- sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
151310
+ pSubq->addrFillSub = addrTop;
151311
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
150875151312
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
150876151313
sqlite3Select(pParse, pSub, &dest);
150877
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
151314
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
150878151315
pItem->fg.viaCoroutine = 1;
150879
- pItem->regResult = dest.iSdst;
150880
- sqlite3VdbeEndCoroutine(v, pItem->regReturn);
151316
+ pSubq->regResult = dest.iSdst;
151317
+ sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
151318
+ VdbeComment((v, "end %!S", pItem));
150881151319
sqlite3VdbeJumpHere(v, addrTop-1);
150882151320
sqlite3ClearTempRegCache(pParse);
150883151321
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
150884151322
/* This is a CTE for which materialization code has already been
150885151323
** generated. Invoke the subroutine to compute the materialization,
150886
- ** the make the pItem->iCursor be a copy of the ephemeral table that
150887
- ** holds the result of the materialization. */
151324
+ ** then make the pItem->iCursor be a copy of the ephemeral table that
151325
+ ** holds the result of the materialization. tag-select-0484 */
150888151326
CteUse *pCteUse = pItem->u2.pCteUse;
150889151327
sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
150890151328
if( pItem->iCursor!=pCteUse->iCur ){
150891151329
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
150892151330
VdbeComment((v, "%!S", pItem));
150893151331
}
150894151332
pSub->nSelectRow = pCteUse->nRowEst;
150895151333
}else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
150896151334
/* This view has already been materialized by a prior entry in
150897
- ** this same FROM clause. Reuse it. */
150898
- if( pPrior->addrFillSub ){
150899
- sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
151335
+ ** this same FROM clause. Reuse it. tag-select-0486 */
151336
+ Subquery *pPriorSubq;
151337
+ assert( pPrior->fg.isSubquery );
151338
+ pPriorSubq = pPrior->u4.pSubq;
151339
+ assert( pPriorSubq!=0 );
151340
+ if( pPriorSubq->addrFillSub ){
151341
+ sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
151342
+ pPriorSubq->addrFillSub);
150900151343
}
150901151344
sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
150902
- pSub->nSelectRow = pPrior->pSelect->nSelectRow;
151345
+ pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
150903151346
}else{
150904151347
/* Materialize the view. If the view is not correlated, generate a
150905151348
** subroutine to do the materialization so that subsequent uses of
150906
- ** the same view can reuse the materialization. */
151349
+ ** the same view can reuse the materialization. tag-select-0488 */
150907151350
int topAddr;
150908151351
int onceAddr = 0;
150909151352
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
150910151353
int addrExplain;
150911151354
#endif
150912151355
150913
- pItem->regReturn = ++pParse->nMem;
151356
+ pSubq->regReturn = ++pParse->nMem;
150914151357
topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
150915
- pItem->addrFillSub = topAddr+1;
151358
+ pSubq->addrFillSub = topAddr+1;
150916151359
pItem->fg.isMaterialized = 1;
150917151360
if( pItem->fg.isCorrelated==0 ){
150918151361
/* If the subquery is not correlated and if we are not inside of
150919151362
** a trigger, then we only need to compute the value of the subquery
150920151363
** once. */
@@ -150925,21 +151368,21 @@
150925151368
}
150926151369
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
150927151370
150928151371
ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
150929151372
sqlite3Select(pParse, pSub, &dest);
150930
- pItem->pTab->nRowLogEst = pSub->nSelectRow;
151373
+ pItem->pSTab->nRowLogEst = pSub->nSelectRow;
150931151374
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
150932
- sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
151375
+ sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
150933151376
VdbeComment((v, "end %!S", pItem));
150934151377
sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
150935151378
sqlite3VdbeJumpHere(v, topAddr);
150936151379
sqlite3ClearTempRegCache(pParse);
150937151380
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
150938151381
CteUse *pCteUse = pItem->u2.pCteUse;
150939
- pCteUse->addrM9e = pItem->addrFillSub;
150940
- pCteUse->regRtn = pItem->regReturn;
151382
+ pCteUse->addrM9e = pSubq->addrFillSub;
151383
+ pCteUse->regRtn = pSubq->regReturn;
150941151384
pCteUse->iCur = pItem->iCursor;
150942151385
pCteUse->nRowEst = pSub->nSelectRow;
150943151386
}
150944151387
}
150945151388
if( db->mallocFailed ) goto select_end;
@@ -150961,11 +151404,13 @@
150961151404
TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
150962151405
sqlite3TreeViewSelect(0, p, 0);
150963151406
}
150964151407
#endif
150965151408
150966
- /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
151409
+ /* tag-select-0500
151410
+ **
151411
+ ** If the query is DISTINCT with an ORDER BY but is not an aggregate, and
150967151412
** if the select-list is the same as the ORDER BY list, then this query
150968151413
** can be rewritten as a GROUP BY. In other words, this:
150969151414
**
150970151415
** SELECT DISTINCT xyz FROM ... ORDER BY xyz
150971151416
**
@@ -151011,11 +151456,11 @@
151011151456
** do the sorting. But this sorting ephemeral index might end up
151012151457
** being unused if the data can be extracted in pre-sorted order.
151013151458
** If that is the case, then the OP_OpenEphemeral instruction will be
151014151459
** changed to an OP_Noop once we figure out that the sorting index is
151015151460
** not needed. The sSort.addrSortIndex variable is used to facilitate
151016
- ** that change.
151461
+ ** that change. tag-select-0600
151017151462
*/
151018151463
if( sSort.pOrderBy ){
151019151464
KeyInfo *pKeyInfo;
151020151465
pKeyInfo = sqlite3KeyInfoFromExprList(
151021151466
pParse, sSort.pOrderBy, 0, pEList->nExpr);
@@ -151028,10 +151473,11 @@
151028151473
}else{
151029151474
sSort.addrSortIndex = -1;
151030151475
}
151031151476
151032151477
/* If the output is destined for a temporary table, open that table.
151478
+ ** tag-select-0630
151033151479
*/
151034151480
if( pDest->eDest==SRT_EphemTab ){
151035151481
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
151036151482
if( p->selFlags & SF_NestedFrom ){
151037151483
/* Delete or NULL-out result columns that will never be used */
@@ -151045,11 +151491,11 @@
151045151491
if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
151046151492
}
151047151493
}
151048151494
}
151049151495
151050
- /* Set the limiter.
151496
+ /* Set the limiter. tag-select-0650
151051151497
*/
151052151498
iEnd = sqlite3VdbeMakeLabel(pParse);
151053151499
if( (p->selFlags & SF_FixedLimit)==0 ){
151054151500
p->nSelectRow = 320; /* 4 billion rows */
151055151501
}
@@ -151057,11 +151503,11 @@
151057151503
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
151058151504
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
151059151505
sSort.sortFlags |= SORTFLAG_UseSorter;
151060151506
}
151061151507
151062
- /* Open an ephemeral index to use for the distinct set.
151508
+ /* Open an ephemeral index to use for the distinct set. tag-select-0680
151063151509
*/
151064151510
if( p->selFlags & SF_Distinct ){
151065151511
sDistinct.tabTnct = pParse->nTab++;
151066151512
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
151067151513
sDistinct.tabTnct, 0, 0,
@@ -151072,11 +151518,11 @@
151072151518
}else{
151073151519
sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
151074151520
}
151075151521
151076151522
if( !isAgg && pGroupBy==0 ){
151077
- /* No aggregate functions and no GROUP BY clause */
151523
+ /* No aggregate functions and no GROUP BY clause. tag-select-0700 */
151078151524
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
151079151525
| (p->selFlags & SF_FixedLimit);
151080151526
#ifndef SQLITE_OMIT_WINDOWFUNC
151081151527
Window *pWin = p->pWin; /* Main window object (or NULL) */
151082151528
if( pWin ){
@@ -151145,12 +151591,12 @@
151145151591
*/
151146151592
TREETRACE(0x2,pParse,p,("WhereEnd\n"));
151147151593
sqlite3WhereEnd(pWInfo);
151148151594
}
151149151595
}else{
151150
- /* This case when there exist aggregate functions or a GROUP BY clause
151151
- ** or both */
151596
+ /* This case is for when there exist aggregate functions or a GROUP BY
151597
+ ** clause or both. tag-select-0800 */
151152151598
NameContext sNC; /* Name context for processing aggregate information */
151153151599
int iAMem; /* First Mem address for storing current GROUP BY */
151154151600
int iBMem; /* First Mem address for previous GROUP BY */
151155151601
int iUseFlag; /* Mem address holding flag indicating that at least
151156151602
** one row of the input to the aggregator has been
@@ -151265,11 +151711,11 @@
151265151711
}
151266151712
#endif
151267151713
151268151714
151269151715
/* Processing for aggregates with GROUP BY is very different and
151270
- ** much more complex than aggregates without a GROUP BY.
151716
+ ** much more complex than aggregates without a GROUP BY. tag-select-0810
151271151717
*/
151272151718
if( pGroupBy ){
151273151719
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
151274151720
int addr1; /* A-vs-B comparison jump */
151275151721
int addrOutputRow; /* Start of subroutine that outputs a result row */
@@ -151562,13 +152008,16 @@
151562152008
struct AggInfo_func *pF = &pAggInfo->aFunc[0];
151563152009
fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
151564152010
}
151565152011
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
151566152012
else {
152013
+ /* Aggregate functions without GROUP BY. tag-select-0820 */
151567152014
Table *pTab;
151568152015
if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
151569
- /* If isSimpleCount() returns a pointer to a Table structure, then
152016
+ /* tag-select-0821
152017
+ **
152018
+ ** If isSimpleCount() returns a pointer to a Table structure, then
151570152019
** the SQL statement is of the form:
151571152020
**
151572152021
** SELECT count(*) FROM <tbl>
151573152022
**
151574152023
** where the Table structure returned represents table <tbl>.
@@ -151623,10 +152072,12 @@
151623152072
assignAggregateRegisters(pParse, pAggInfo);
151624152073
sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
151625152074
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
151626152075
explainSimpleCount(pParse, pTab, pBest);
151627152076
}else{
152077
+ /* The general case of an aggregate query without GROUP BY
152078
+ ** tag-select-0822 */
151628152079
int regAcc = 0; /* "populate accumulators" flag */
151629152080
ExprList *pDistinct = 0;
151630152081
u16 distFlag = 0;
151631152082
int eDist;
151632152083
@@ -151711,11 +152162,11 @@
151711152162
if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
151712152163
explainTempTable(pParse, "DISTINCT");
151713152164
}
151714152165
151715152166
/* If there is an ORDER BY clause, then we need to sort the results
151716
- ** and send them to the callback one by one.
152167
+ ** and send them to the callback one by one. tag-select-0900
151717152168
*/
151718152169
if( sSort.pOrderBy ){
151719152170
assert( p->pEList==pEList );
151720152171
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
151721152172
}
@@ -151734,10 +152185,11 @@
151734152185
select_end:
151735152186
assert( db->mallocFailed==0 || db->mallocFailed==1 );
151736152187
assert( db->mallocFailed==0 || pParse->nErr!=0 );
151737152188
sqlite3ExprListDelete(db, pMinMaxOrderBy);
151738152189
#ifdef SQLITE_DEBUG
152190
+ /* Internal self-checks. tag-select-1000 */
151739152191
if( pAggInfo && !db->mallocFailed ){
151740152192
#if TREETRACE_ENABLED
151741152193
if( sqlite3TreeTrace & 0x20 ){
151742152194
TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
151743152195
printAggInfo(pAggInfo);
@@ -152123,12 +152575,14 @@
152123152575
**
152124152576
** To maintain backwards compatibility, ignore the database
152125152577
** name on pTableName if we are reparsing out of the schema table
152126152578
*/
152127152579
if( db->init.busy && iDb!=1 ){
152128
- sqlite3DbFree(db, pTableName->a[0].zDatabase);
152129
- pTableName->a[0].zDatabase = 0;
152580
+ assert( pTableName->a[0].fg.fixedSchema==0 );
152581
+ assert( pTableName->a[0].fg.isSubquery==0 );
152582
+ sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
152583
+ pTableName->a[0].u4.zDatabase = 0;
152130152584
}
152131152585
152132152586
/* If the trigger name was unqualified, and the table is a temp table,
152133152587
** then set iDb to 1 to create the trigger in the temporary database.
152134152588
** If sqlite3SrcListLookup() returns 0, indicating the table does not
@@ -152602,11 +153056,12 @@
152602153056
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
152603153057
goto drop_trigger_cleanup;
152604153058
}
152605153059
152606153060
assert( pName->nSrc==1 );
152607
- zDb = pName->a[0].zDatabase;
153061
+ assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
153062
+ zDb = pName->a[0].u4.zDatabase;
152608153063
zName = pName->a[0].zName;
152609153064
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
152610153065
for(i=OMIT_TEMPDB; i<db->nDb; i++){
152611153066
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
152612153067
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
@@ -152839,11 +153294,13 @@
152839153294
assert( zName || pSrc==0 );
152840153295
if( pSrc ){
152841153296
Schema *pSchema = pStep->pTrig->pSchema;
152842153297
pSrc->a[0].zName = zName;
152843153298
if( pSchema!=db->aDb[1].pSchema ){
152844
- pSrc->a[0].pSchema = pSchema;
153299
+ assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
153300
+ pSrc->a[0].u4.pSchema = pSchema;
153301
+ pSrc->a[0].fg.fixedSchema = 1;
152845153302
}
152846153303
if( pStep->pFrom ){
152847153304
SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
152848153305
if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
152849153306
Select *pSubquery;
@@ -152952,11 +153409,11 @@
152952153409
SrcList *pSrc;
152953153410
assert( pSelect!=0 );
152954153411
pSrc = pSelect->pSrc;
152955153412
assert( pSrc!=0 );
152956153413
for(i=0; i<pSrc->nSrc; i++){
152957
- if( pSrc->a[i].pTab==pWalker->u.pTab ){
153414
+ if( pSrc->a[i].pSTab==pWalker->u.pTab ){
152958153415
testcase( pSelect->selFlags & SF_Correlated );
152959153416
pSelect->selFlags |= SF_Correlated;
152960153417
pWalker->eCode = 1;
152961153418
break;
152962153419
}
@@ -153023,11 +153480,11 @@
153023153480
memset(&sSelect, 0, sizeof(sSelect));
153024153481
memset(&sFrom, 0, sizeof(sFrom));
153025153482
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
153026153483
sSelect.pSrc = &sFrom;
153027153484
sFrom.nSrc = 1;
153028
- sFrom.a[0].pTab = pTab;
153485
+ sFrom.a[0].pSTab = pTab;
153029153486
sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
153030153487
sFrom.a[0].iCursor = -1;
153031153488
sqlite3SelectPrep(pParse, &sSelect, 0);
153032153489
if( pParse->nErr==0 ){
153033153490
assert( db->mallocFailed==0 );
@@ -153734,11 +154191,11 @@
153734154191
ExprList *pList = 0;
153735154192
ExprList *pGrp = 0;
153736154193
Expr *pLimit2 = 0;
153737154194
ExprList *pOrderBy2 = 0;
153738154195
sqlite3 *db = pParse->db;
153739
- Table *pTab = pTabList->a[0].pTab;
154196
+ Table *pTab = pTabList->a[0].pSTab;
153740154197
SrcList *pSrc;
153741154198
Expr *pWhere2;
153742154199
int eDest;
153743154200
153744154201
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -153758,12 +154215,12 @@
153758154215
153759154216
assert( pTabList->nSrc>1 );
153760154217
if( pSrc ){
153761154218
assert( pSrc->a[0].fg.notCte );
153762154219
pSrc->a[0].iCursor = -1;
153763
- pSrc->a[0].pTab->nTabRef--;
153764
- pSrc->a[0].pTab = 0;
154220
+ pSrc->a[0].pSTab->nTabRef--;
154221
+ pSrc->a[0].pSTab = 0;
153765154222
}
153766154223
if( pPk ){
153767154224
for(i=0; i<pPk->nKeyCol; i++){
153768154225
Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
153769154226
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -155007,11 +155464,11 @@
155007155464
NameContext sNC; /* Context for resolving symbolic names */
155008155465
Expr sCol[2]; /* Index column converted into an Expr */
155009155466
int nClause = 0; /* Counter of ON CONFLICT clauses */
155010155467
155011155468
assert( pTabList->nSrc==1 );
155012
- assert( pTabList->a[0].pTab!=0 );
155469
+ assert( pTabList->a[0].pSTab!=0 );
155013155470
assert( pUpsert!=0 );
155014155471
assert( pUpsert->pUpsertTarget!=0 );
155015155472
155016155473
/* Resolve all symbolic names in the conflict-target clause, which
155017155474
** includes both the list of columns and the optional partial-index
@@ -155026,11 +155483,11 @@
155026155483
if( rc ) return rc;
155027155484
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
155028155485
if( rc ) return rc;
155029155486
155030155487
/* Check to see if the conflict target matches the rowid. */
155031
- pTab = pTabList->a[0].pTab;
155488
+ pTab = pTabList->a[0].pSTab;
155032155489
pTarget = pUpsert->pUpsertTarget;
155033155490
iCursor = pTabList->a[0].iCursor;
155034155491
if( HasRowid(pTab)
155035155492
&& pTarget->nExpr==1
155036155493
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
@@ -155397,10 +155854,13 @@
155397155854
int nRes; /* Bytes of reserved space at the end of each page */
155398155855
int nDb; /* Number of attached databases */
155399155856
const char *zDbMain; /* Schema name of database to vacuum */
155400155857
const char *zOut; /* Name of output file */
155401155858
u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
155859
+ u64 iRandom; /* Random value used for zDbVacuum[] */
155860
+ char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
155861
+
155402155862
155403155863
if( !db->autoCommit ){
155404155864
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
155405155865
return SQLITE_ERROR; /* IMP: R-12218-18073 */
155406155866
}
@@ -155437,31 +155897,33 @@
155437155897
155438155898
zDbMain = db->aDb[iDb].zDbSName;
155439155899
pMain = db->aDb[iDb].pBt;
155440155900
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
155441155901
155442
- /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
155902
+ /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
155443155903
** can be set to 'off' for this file, as it is not recovered if a crash
155444155904
** occurs anyway. The integrity of the database is maintained by a
155445155905
** (possibly synchronous) transaction opened on the main database before
155446155906
** sqlite3BtreeCopyFile() is called.
155447155907
**
155448155908
** An optimization would be to use a non-journaled pager.
155449
- ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
155909
+ ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
155450155910
** that actually made the VACUUM run slower. Very little journalling
155451155911
** actually occurs when doing a vacuum since the vacuum_db is initially
155452155912
** empty. Only the journal header is written. Apparently it takes more
155453155913
** time to parse and run the PRAGMA to turn journalling off than it does
155454155914
** to write the journal header file.
155455155915
*/
155916
+ sqlite3_randomness(sizeof(iRandom),&iRandom);
155917
+ sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
155456155918
nDb = db->nDb;
155457
- rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
155919
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
155458155920
db->openFlags = saved_openFlags;
155459155921
if( rc!=SQLITE_OK ) goto end_of_vacuum;
155460155922
assert( (db->nDb-1)==nDb );
155461155923
pDb = &db->aDb[nDb];
155462
- assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
155924
+ assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
155463155925
pTemp = pDb->pBt;
155464155926
if( pOut ){
155465155927
sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
155466155928
i64 sz = 0;
155467155929
if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
@@ -155534,15 +155996,15 @@
155534155996
/* Loop through the tables in the main database. For each, do
155535155997
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
155536155998
** the contents to the temporary database.
155537155999
*/
155538156000
rc = execSqlF(db, pzErrMsg,
155539
- "SELECT'INSERT INTO vacuum_db.'||quote(name)"
156001
+ "SELECT'INSERT INTO %s.'||quote(name)"
155540156002
"||' SELECT*FROM\"%w\".'||quote(name)"
155541
- "FROM vacuum_db.sqlite_schema "
156003
+ "FROM %s.sqlite_schema "
155542156004
"WHERE type='table'AND coalesce(rootpage,1)>0",
155543
- zDbMain
156005
+ zDbVacuum, zDbMain, zDbVacuum
155544156006
);
155545156007
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
155546156008
db->mDbFlags &= ~DBFLAG_Vacuum;
155547156009
if( rc!=SQLITE_OK ) goto end_of_vacuum;
155548156010
@@ -155550,15 +156012,15 @@
155550156012
** over to the temporary database. None of these objects has any
155551156013
** associated storage, so all we have to do is copy their entries
155552156014
** from the schema table.
155553156015
*/
155554156016
rc = execSqlF(db, pzErrMsg,
155555
- "INSERT INTO vacuum_db.sqlite_schema"
156017
+ "INSERT INTO %s.sqlite_schema"
155556156018
" SELECT*FROM \"%w\".sqlite_schema"
155557156019
" WHERE type IN('view','trigger')"
155558156020
" OR(type='table'AND rootpage=0)",
155559
- zDbMain
156021
+ zDbVacuum, zDbMain
155560156022
);
155561156023
if( rc ) goto end_of_vacuum;
155562156024
155563156025
/* At this point, there is a write transaction open on both the
155564156026
** vacuum database and the main database. Assuming no error occurs,
@@ -157198,10 +157660,11 @@
157198157660
} btree;
157199157661
struct { /* Information for virtual tables */
157200157662
int idxNum; /* Index number */
157201157663
u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
157202157664
u32 bOmitOffset : 1; /* True to let virtual table handle offset */
157665
+ u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */
157203157666
i8 isOrdered; /* True if satisfies ORDER BY */
157204157667
u16 omitMask; /* Terms that may be omitted */
157205157668
char *idxStr; /* Index identifier string */
157206157669
u32 mHandleIn; /* Terms to handle as IN(...) instead of == */
157207157670
} vtab;
@@ -157832,11 +158295,11 @@
157832158295
Index *pIdx;
157833158296
157834158297
assert( pLoop->u.btree.pIndex!=0 );
157835158298
pIdx = pLoop->u.btree.pIndex;
157836158299
assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
157837
- if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
158300
+ if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
157838158301
if( isSearch ){
157839158302
zFmt = "PRIMARY KEY";
157840158303
}
157841158304
}else if( flags & WHERE_PARTIALIDX ){
157842158305
zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
@@ -157875,11 +158338,13 @@
157875158338
}
157876158339
sqlite3_str_appendf(&str, "%c?)", cRangeOp);
157877158340
}
157878158341
#ifndef SQLITE_OMIT_VIRTUALTABLE
157879158342
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
157880
- sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
158343
+ sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX ");
158344
+ sqlite3_str_appendf(&str,
158345
+ pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s",
157881158346
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
157882158347
}
157883158348
#endif
157884158349
if( pItem->fg.jointype & JT_LEFT ){
157885158350
sqlite3_str_appendf(&str, " LEFT-JOIN");
@@ -157929,11 +158394,11 @@
157929158394
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
157930158395
str.printfFlags = SQLITE_PRINTF_INTERNAL;
157931158396
sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
157932158397
pLoop = pLevel->pWLoop;
157933158398
if( pLoop->wsFlags & WHERE_IPK ){
157934
- const Table *pTab = pItem->pTab;
158399
+ const Table *pTab = pItem->pSTab;
157935158400
if( pTab->iPKey>=0 ){
157936158401
sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
157937158402
}else{
157938158403
sqlite3_str_appendf(&str, "rowid=?");
157939158404
}
@@ -157992,11 +158457,13 @@
157992158457
}
157993158458
if( wsFlags & WHERE_INDEXED ){
157994158459
sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
157995158460
}
157996158461
}else{
157997
- int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
158462
+ int addr;
158463
+ assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
158464
+ addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
157998158465
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
157999158466
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158000158467
assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158001158468
sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158002158469
}
@@ -159129,11 +159596,12 @@
159129159596
pLoop = pLevel->pWLoop;
159130159597
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
159131159598
iCur = pTabItem->iCursor;
159132159599
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
159133159600
bRev = (pWInfo->revMask>>iLevel)&1;
159134
- VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
159601
+ VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
159602
+ iLevel, pTabItem->pSTab->zName));
159135159603
#if WHERETRACE_ENABLED /* 0x4001 */
159136159604
if( sqlite3WhereTrace & 0x1 ){
159137159605
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
159138159606
iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
159139159607
if( sqlite3WhereTrace & 0x1000 ){
@@ -159184,15 +159652,19 @@
159184159652
}
159185159653
addrHalt = pWInfo->a[j].addrBrk;
159186159654
159187159655
/* Special case of a FROM clause subquery implemented as a co-routine */
159188159656
if( pTabItem->fg.viaCoroutine ){
159189
- int regYield = pTabItem->regReturn;
159190
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
159657
+ int regYield;
159658
+ Subquery *pSubq;
159659
+ assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
159660
+ pSubq = pTabItem->u4.pSubq;
159661
+ regYield = pSubq->regReturn;
159662
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
159191159663
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
159192159664
VdbeCoverage(v);
159193
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
159665
+ VdbeComment((v, "next row of %s", pTabItem->pSTab->zName));
159194159666
pLevel->op = OP_Goto;
159195159667
}else
159196159668
159197159669
#ifndef SQLITE_OMIT_VIRTUALTABLE
159198159670
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
@@ -159917,11 +160389,11 @@
159917160389
int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */
159918160390
int iRetInit; /* Address of regReturn init */
159919160391
int untestedTerms = 0; /* Some terms not completely tested */
159920160392
int ii; /* Loop counter */
159921160393
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
159922
- Table *pTab = pTabItem->pTab;
160394
+ Table *pTab = pTabItem->pSTab;
159923160395
159924160396
pTerm = pLoop->aLTerm[0];
159925160397
assert( pTerm!=0 );
159926160398
assert( pTerm->eOperator & WO_OR );
159927160399
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
@@ -160376,11 +160848,11 @@
160376160848
/* pTab is the right-hand table of the RIGHT JOIN. Generate code that
160377160849
** will record that the current row of that table has been matched at
160378160850
** least once. This is accomplished by storing the PK for the row in
160379160851
** both the iMatch index and the regBloom Bloom filter.
160380160852
*/
160381
- pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
160853
+ pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
160382160854
if( HasRowid(pTab) ){
160383160855
r = sqlite3GetTempRange(pParse, 2);
160384160856
sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
160385160857
nPk = 1;
160386160858
}else{
@@ -160483,23 +160955,27 @@
160483160955
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
160484160956
SrcList sFrom;
160485160957
Bitmask mAll = 0;
160486160958
int k;
160487160959
160488
- ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
160960
+ ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
160489160961
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
160490160962
pRJ->regReturn);
160491160963
for(k=0; k<iLevel; k++){
160492160964
int iIdxCur;
160493160965
SrcItem *pRight;
160494160966
assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
160495160967
pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
160496160968
mAll |= pWInfo->a[k].pWLoop->maskSelf;
160497160969
if( pRight->fg.viaCoroutine ){
160970
+ Subquery *pSubq;
160971
+ assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
160972
+ pSubq = pRight->u4.pSubq;
160973
+ assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
160498160974
sqlite3VdbeAddOp3(
160499
- v, OP_Null, 0, pRight->regResult,
160500
- pRight->regResult + pRight->pSelect->pEList->nExpr-1
160975
+ v, OP_Null, 0, pSubq->regResult,
160976
+ pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
160501160977
);
160502160978
}
160503160979
sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
160504160980
iIdxCur = pWInfo->a[k].iIdxCur;
160505160981
if( iIdxCur ){
@@ -160533,11 +161009,11 @@
160533161009
int iCur = pLevel->iTabCur;
160534161010
int r = ++pParse->nMem;
160535161011
int nPk;
160536161012
int jmp;
160537161013
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
160538
- Table *pTab = pTabItem->pTab;
161014
+ Table *pTab = pTabItem->pSTab;
160539161015
if( HasRowid(pTab) ){
160540161016
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
160541161017
nPk = 1;
160542161018
}else{
160543161019
int iPk;
@@ -160785,15 +161261,24 @@
160785161261
assert( !ExprHasProperty(pRight, EP_IntValue) );
160786161262
z = (u8*)pRight->u.zToken;
160787161263
}
160788161264
if( z ){
160789161265
160790
- /* Count the number of prefix characters prior to the first wildcard */
161266
+ /* Count the number of prefix characters prior to the first wildcard.
161267
+ ** If the underlying database has a UTF16LE encoding, then only consider
161268
+ ** ASCII characters. Note that the encoding of z[] is UTF8 - we are
161269
+ ** dealing with only UTF8 here in this code, but the database engine
161270
+ ** itself might be processing content using a different encoding. */
160791161271
cnt = 0;
160792161272
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
160793161273
cnt++;
160794
- if( c==wc[3] && z[cnt]!=0 ) cnt++;
161274
+ if( c==wc[3] && z[cnt]!=0 ){
161275
+ cnt++;
161276
+ }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){
161277
+ cnt--;
161278
+ break;
161279
+ }
160795161280
}
160796161281
160797161282
/* The optimization is possible only if (1) the pattern does not begin
160798161283
** with a wildcard and if (2) the non-wildcard prefix does not end with
160799161284
** an (illegal 0xff) character, or (3) the pattern does not consist of
@@ -160804,11 +161289,11 @@
160804161289
** removed. */
160805161290
if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
160806161291
Expr *pPrefix;
160807161292
160808161293
/* A "complete" match if the pattern ends with "*" or "%" */
160809
- *pisComplete = c==wc[0] && z[cnt+1]==0;
161294
+ *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
160810161295
160811161296
/* Get the pattern prefix. Remove all escapes from the prefix. */
160812161297
pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
160813161298
if( pPrefix ){
160814161299
int iFrom, iTo;
@@ -161523,11 +162008,13 @@
161523162008
mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere);
161524162009
mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving);
161525162010
if( ALWAYS(pSrc!=0) ){
161526162011
int i;
161527162012
for(i=0; i<pSrc->nSrc; i++){
161528
- mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
162013
+ if( pSrc->a[i].fg.isSubquery ){
162014
+ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
162015
+ }
161529162016
if( pSrc->a[i].fg.isUsing==0 ){
161530162017
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
161531162018
}
161532162019
if( pSrc->a[i].fg.isTabFunc ){
161533162020
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
@@ -161561,11 +162048,11 @@
161561162048
Index *pIdx;
161562162049
int i;
161563162050
int iCur;
161564162051
do{
161565162052
iCur = pFrom->a[j].iCursor;
161566
- for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
162053
+ for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
161567162054
if( pIdx->aColExpr==0 ) continue;
161568162055
for(i=0; i<pIdx->nKeyCol; i++){
161569162056
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
161570162057
assert( pIdx->bHasExpr );
161571162058
if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
@@ -161605,11 +162092,11 @@
161605162092
return 1;
161606162093
}
161607162094
161608162095
for(i=0; i<pFrom->nSrc; i++){
161609162096
Index *pIdx;
161610
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
162097
+ for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
161611162098
if( pIdx->aColExpr ){
161612162099
return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
161613162100
}
161614162101
}
161615162102
}
@@ -162193,11 +162680,11 @@
162193162680
*/
162194162681
SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
162195162682
assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
162196162683
if( p->pGroupBy==0
162197162684
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
162198
- && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
162685
+ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
162199162686
){
162200162687
ExprList *pOrderBy = p->pOrderBy;
162201162688
int iCsr = p->pSrc->a[0].iCursor;
162202162689
int ii;
162203162690
@@ -162414,11 +162901,11 @@
162414162901
int j, k;
162415162902
ExprList *pArgs;
162416162903
Expr *pColRef;
162417162904
Expr *pTerm;
162418162905
if( pItem->fg.isTabFunc==0 ) return;
162419
- pTab = pItem->pTab;
162906
+ pTab = pItem->pSTab;
162420162907
assert( pTab!=0 );
162421162908
pArgs = pItem->u1.pFuncArg;
162422162909
if( pArgs==0 ) return;
162423162910
for(j=k=0; j<pArgs->nExpr; j++){
162424162911
Expr *pRhs;
@@ -163098,11 +163585,11 @@
163098163585
/* If there is more than one table or sub-select in the FROM clause of
163099163586
** this query, then it will not be possible to show that the DISTINCT
163100163587
** clause is redundant. */
163101163588
if( pTabList->nSrc!=1 ) return 0;
163102163589
iBase = pTabList->a[0].iCursor;
163103
- pTab = pTabList->a[0].pTab;
163590
+ pTab = pTabList->a[0].pSTab;
163104163591
163105163592
/* If any of the expressions is an IPK column on table iBase, then return
163106163593
** true. Note: The (p->iTable==iBase) part of this test may be false if the
163107163594
** current SELECT is a correlated sub-query.
163108163595
*/
@@ -163362,14 +163849,14 @@
163362163849
}
163363163850
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
163364163851
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
163365163852
leftCol = pTerm->u.x.leftColumn;
163366163853
if( leftCol<0 ) return 0;
163367
- aff = pSrc->pTab->aCol[leftCol].affinity;
163854
+ aff = pSrc->pSTab->aCol[leftCol].affinity;
163368163855
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
163369163856
testcase( pTerm->pExpr->op==TK_IS );
163370
- return columnIsGoodIndexCandidate(pSrc->pTab, leftCol);
163857
+ return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
163371163858
}
163372163859
#endif
163373163860
163374163861
163375163862
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -163473,11 +163960,11 @@
163473163960
/* Count the number of columns that will be added to the index
163474163961
** and used to match WHERE clause constraints */
163475163962
nKeyCol = 0;
163476163963
pTabList = pWC->pWInfo->pTabList;
163477163964
pSrc = &pTabList->a[pLevel->iFrom];
163478
- pTable = pSrc->pTab;
163965
+ pTable = pSrc->pSTab;
163479163966
pWCEnd = &pWC->a[pWC->nTerm];
163480163967
pLoop = pLevel->pWLoop;
163481163968
idxCols = 0;
163482163969
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
163483163970
Expr *pExpr = pTerm->pExpr;
@@ -163615,16 +164102,21 @@
163615164102
}
163616164103
163617164104
/* Fill the automatic index with content */
163618164105
assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
163619164106
if( pSrc->fg.viaCoroutine ){
163620
- int regYield = pSrc->regReturn;
164107
+ int regYield;
164108
+ Subquery *pSubq;
164109
+ assert( pSrc->fg.isSubquery );
164110
+ pSubq = pSrc->u4.pSubq;
164111
+ assert( pSubq!=0 );
164112
+ regYield = pSubq->regReturn;
163621164113
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
163622
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
164114
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
163623164115
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
163624164116
VdbeCoverage(v);
163625
- VdbeComment((v, "next row of %s", pSrc->pTab->zName));
164117
+ VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
163626164118
}else{
163627164119
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
163628164120
}
163629164121
if( pPartial ){
163630164122
iContinue = sqlite3VdbeMakeLabel(pParse);
@@ -163642,15 +164134,16 @@
163642164134
sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v));
163643164135
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
163644164136
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
163645164137
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
163646164138
if( pSrc->fg.viaCoroutine ){
164139
+ assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
163647164140
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
163648164141
testcase( pParse->db->mallocFailed );
163649164142
assert( pLevel->iIdxCur>0 );
163650164143
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
163651
- pSrc->regResult, pLevel->iIdxCur);
164144
+ pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
163652164145
sqlite3VdbeGoto(v, addrTop);
163653164146
pSrc->fg.viaCoroutine = 0;
163654164147
}else{
163655164148
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
163656164149
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -163737,11 +164230,11 @@
163737164230
*/
163738164231
pTabList = pWInfo->pTabList;
163739164232
iSrc = pLevel->iFrom;
163740164233
pItem = &pTabList->a[iSrc];
163741164234
assert( pItem!=0 );
163742
- pTab = pItem->pTab;
164235
+ pTab = pItem->pSTab;
163743164236
assert( pTab!=0 );
163744164237
sz = sqlite3LogEstToInt(pTab->nRowLogEst);
163745164238
if( sz<10000 ){
163746164239
sz = 10000;
163747164240
}else if( sz>10000000 ){
@@ -163768,11 +164261,11 @@
163768164261
Index *pIdx = pLoop->u.btree.pIndex;
163769164262
int n = pLoop->u.btree.nEq;
163770164263
int r1 = sqlite3GetTempRange(pParse, n);
163771164264
int jj;
163772164265
for(jj=0; jj<n; jj++){
163773
- assert( pIdx->pTable==pItem->pTab );
164266
+ assert( pIdx->pTable==pItem->pSTab );
163774164267
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
163775164268
}
163776164269
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
163777164270
sqlite3ReleaseTempRange(pParse, r1, n);
163778164271
}
@@ -163849,11 +164342,11 @@
163849164342
int eDistinct = 0;
163850164343
ExprList *pOrderBy = pWInfo->pOrderBy;
163851164344
WhereClause *p;
163852164345
163853164346
assert( pSrc!=0 );
163854
- pTab = pSrc->pTab;
164347
+ pTab = pSrc->pSTab;
163855164348
assert( pTab!=0 );
163856164349
assert( IsVirtual(pTab) );
163857164350
163858164351
/* Find all WHERE clause constraints referring to this virtual table.
163859164352
** Mark each term with the TERM_OK flag. Set nTerm to the number of
@@ -164857,11 +165350,11 @@
164857165350
SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
164858165351
if( pWC ){
164859165352
WhereInfo *pWInfo = pWC->pWInfo;
164860165353
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
164861165354
SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
164862
- Table *pTab = pItem->pTab;
165355
+ Table *pTab = pItem->pSTab;
164863165356
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
164864165357
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
164865165358
p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
164866165359
sqlite3DebugPrintf(" %12s",
164867165360
pItem->zAlias ? pItem->zAlias : pTab->zName);
@@ -165845,19 +166338,19 @@
165845166338
** 1. The cost of doing one search-by-key to find the first matching
165846166339
** entry
165847166340
** 2. Stepping forward in the index pNew->nOut times to find all
165848166341
** additional matching entries.
165849166342
*/
165850
- assert( pSrc->pTab->szTabRow>0 );
166343
+ assert( pSrc->pSTab->szTabRow>0 );
165851166344
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
165852166345
/* The pProbe->szIdxRow is low for an IPK table since the interior
165853166346
** pages are small. Thus szIdxRow gives a good estimate of seek cost.
165854166347
** But the leaf pages are full-size, so pProbe->szIdxRow would badly
165855166348
** under-estimate the scanning cost. */
165856166349
rCostIdx = pNew->nOut + 16;
165857166350
}else{
165858
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
166351
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
165859166352
}
165860166353
rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
165861166354
165862166355
/* Estimate the cost of running the loop. If all data is coming
165863166356
** from the index, then this is just the cost of doing the index
@@ -166318,13 +166811,13 @@
166318166811
166319166812
pNew = pBuilder->pNew;
166320166813
pWInfo = pBuilder->pWInfo;
166321166814
pTabList = pWInfo->pTabList;
166322166815
pSrc = pTabList->a + pNew->iTab;
166323
- pTab = pSrc->pTab;
166816
+ pTab = pSrc->pSTab;
166324166817
pWC = pBuilder->pWC;
166325
- assert( !IsVirtual(pSrc->pTab) );
166818
+ assert( !IsVirtual(pSrc->pSTab) );
166326166819
166327166820
if( pSrc->fg.isIndexedBy ){
166328166821
assert( pSrc->fg.isCte==0 );
166329166822
/* An INDEXED BY clause specifies a particular index to use */
166330166823
pProbe = pSrc->u2.pIBIndex;
@@ -166345,11 +166838,11 @@
166345166838
sPk.pTable = pTab;
166346166839
sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
166347166840
sPk.idxType = SQLITE_IDXTYPE_IPK;
166348166841
aiRowEstPk[0] = pTab->nRowLogEst;
166349166842
aiRowEstPk[1] = 0;
166350
- pFirst = pSrc->pTab->pIndex;
166843
+ pFirst = pSrc->pSTab->pIndex;
166351166844
if( pSrc->fg.notIndexed==0 ){
166352166845
/* The real indices of the table are only considered if the
166353166846
** NOT INDEXED qualifier is omitted from the FROM clause */
166354166847
sPk.pNext = pFirst;
166355166848
}
@@ -166435,10 +166928,11 @@
166435166928
pNew->iSortIdx = 0;
166436166929
pNew->rSetup = 0;
166437166930
pNew->prereq = mPrereq;
166438166931
pNew->nOut = rSize;
166439166932
pNew->u.btree.pIndex = pProbe;
166933
+ pNew->u.btree.pOrderBy = 0;
166440166934
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
166441166935
166442166936
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
166443166937
assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
166444166938
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
@@ -166464,13 +166958,13 @@
166464166958
#else
166465166959
pNew->rRun = rSize + 16;
166466166960
#endif
166467166961
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
166468166962
whereLoopOutputAdjust(pWC, pNew, rSize);
166469
- if( pSrc->pSelect ){
166963
+ if( pSrc->fg.isSubquery ){
166470166964
if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
166471
- pNew->u.btree.pOrderBy = pSrc->pSelect->pOrderBy;
166965
+ pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
166472166966
}
166473166967
rc = whereLoopInsert(pBuilder, pNew);
166474166968
pNew->nOut = rSize;
166475166969
if( rc ) break;
166476166970
}else{
@@ -166692,11 +167186,11 @@
166692167186
pIdxInfo->estimatedRows = 25;
166693167187
pIdxInfo->idxFlags = 0;
166694167188
pHidden->mHandleIn = 0;
166695167189
166696167190
/* Invoke the virtual table xBestIndex() method */
166697
- rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
167191
+ rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
166698167192
if( rc ){
166699167193
if( rc==SQLITE_CONSTRAINT ){
166700167194
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
166701167195
** that the particular combination of parameters provided is unusable.
166702167196
** Make no entries in the loop table.
@@ -166722,11 +167216,11 @@
166722167216
|| j<0
166723167217
|| (pTerm = termFromWhereClause(pWC, j))==0
166724167218
|| pNew->aLTerm[iTerm]!=0
166725167219
|| pIdxCons->usable==0
166726167220
){
166727
- sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
167221
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
166728167222
freeIdxStr(pIdxInfo);
166729167223
return SQLITE_ERROR;
166730167224
}
166731167225
testcase( iTerm==nConstraint-1 );
166732167226
testcase( j==0 );
@@ -166785,11 +167279,11 @@
166785167279
pNew->nLTerm = mxTerm+1;
166786167280
for(i=0; i<=mxTerm; i++){
166787167281
if( pNew->aLTerm[i]==0 ){
166788167282
/* The non-zero argvIdx values must be contiguous. Raise an
166789167283
** error if they are not */
166790
- sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
167284
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
166791167285
freeIdxStr(pIdxInfo);
166792167286
return SQLITE_ERROR;
166793167287
}
166794167288
}
166795167289
assert( pNew->nLTerm<=pNew->nLSlot );
@@ -166797,10 +167291,11 @@
166797167291
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
166798167292
pIdxInfo->needToFreeIdxStr = 0;
166799167293
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
166800167294
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
166801167295
pIdxInfo->nOrderBy : 0);
167296
+ pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0;
166802167297
pNew->rSetup = 0;
166803167298
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
166804167299
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
166805167300
166806167301
/* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
@@ -166987,11 +167482,11 @@
166987167482
pWInfo = pBuilder->pWInfo;
166988167483
pParse = pWInfo->pParse;
166989167484
pWC = pBuilder->pWC;
166990167485
pNew = pBuilder->pNew;
166991167486
pSrc = &pWInfo->pTabList->a[pNew->iTab];
166992
- assert( IsVirtual(pSrc->pTab) );
167487
+ assert( IsVirtual(pSrc->pSTab) );
166993167488
p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
166994167489
if( p==0 ) return SQLITE_NOMEM_BKPT;
166995167490
pNew->rSetup = 0;
166996167491
pNew->wsFlags = WHERE_VIRTUALTABLE;
166997167492
pNew->nLTerm = 0;
@@ -167001,11 +167496,11 @@
167001167496
freeIndexInfo(pParse->db, p);
167002167497
return SQLITE_NOMEM_BKPT;
167003167498
}
167004167499
167005167500
/* First call xBestIndex() with all constraints usable. */
167006
- WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
167501
+ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
167007167502
WHERETRACE(0x800, (" VirtualOne: all usable\n"));
167008167503
rc = whereLoopAddVirtualOne(
167009167504
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
167010167505
);
167011167506
if( bRetry ){
@@ -167083,11 +167578,11 @@
167083167578
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
167084167579
}
167085167580
}
167086167581
167087167582
freeIndexInfo(pParse->db, p);
167088
- WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
167583
+ WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
167089167584
return rc;
167090167585
}
167091167586
#endif /* SQLITE_OMIT_VIRTUALTABLE */
167092167587
167093167588
/*
@@ -167155,11 +167650,11 @@
167155167650
if( sqlite3WhereTrace & 0x20000 ){
167156167651
sqlite3WhereClausePrint(sSubBuild.pWC);
167157167652
}
167158167653
#endif
167159167654
#ifndef SQLITE_OMIT_VIRTUALTABLE
167160
- if( IsVirtual(pItem->pTab) ){
167655
+ if( IsVirtual(pItem->pSTab) ){
167161167656
rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
167162167657
}else
167163167658
#endif
167164167659
{
167165167660
rc = whereLoopAddBtree(&sSubBuild, mPrereq);
@@ -167269,11 +167764,11 @@
167269167764
bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0;
167270167765
}else if( !hasRightJoin ){
167271167766
mPrereq = 0;
167272167767
}
167273167768
#ifndef SQLITE_OMIT_VIRTUALTABLE
167274
- if( IsVirtual(pItem->pTab) ){
167769
+ if( IsVirtual(pItem->pSTab) ){
167275167770
SrcItem *p;
167276167771
for(p=&pItem[1]; p<pEnd; p++){
167277167772
if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
167278167773
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
167279167774
}
@@ -167905,11 +168400,11 @@
167905168400
rDelta = 15*(nDep-3);
167906168401
#ifdef WHERETRACE_ENABLED /* 0x4 */
167907168402
if( sqlite3WhereTrace&0x4 ){
167908168403
SrcItem *pItem = pWInfo->pTabList->a + iLoop;
167909168404
sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
167910
- pItem->zAlias ? pItem->zAlias : pItem->pTab->zName,
168405
+ pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
167911168406
nDep, rDelta);
167912168407
}
167913168408
#endif
167914168409
if( pWInfo->nOutStarDelta==0 ){
167915168410
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
@@ -168455,11 +168950,11 @@
168455168950
168456168951
pWInfo = pBuilder->pWInfo;
168457168952
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
168458168953
assert( pWInfo->pTabList->nSrc>=1 );
168459168954
pItem = pWInfo->pTabList->a;
168460
- pTab = pItem->pTab;
168955
+ pTab = pItem->pSTab;
168461168956
if( IsVirtual(pTab) ) return 0;
168462168957
if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
168463168958
testcase( pItem->fg.isIndexedBy );
168464168959
testcase( pItem->fg.notIndexed );
168465168960
return 0;
@@ -168718,11 +169213,11 @@
168718169213
assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
168719169214
for(i=0; i<pWInfo->nLevel; i++){
168720169215
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
168721169216
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
168722169217
SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
168723
- Table *pTab = pItem->pTab;
169218
+ Table *pTab = pItem->pSTab;
168724169219
if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
168725169220
pTab->tabFlags |= TF_MaybeReanalyze;
168726169221
if( i>=1
168727169222
&& (pLoop->wsFlags & reqFlags)==reqFlags
168728169223
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
@@ -168875,12 +169370,12 @@
168875169370
int ii;
168876169371
for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
168877169372
SrcItem *pItem = &pWInfo->pTabList->a[ii];
168878169373
if( !pItem->fg.isCte
168879169374
|| pItem->u2.pCteUse->eM10d!=M10d_Yes
168880
- || NEVER(pItem->pSelect==0)
168881
- || pItem->pSelect->pOrderBy==0
169375
+ || NEVER(pItem->fg.isSubquery==0)
169376
+ || pItem->u4.pSubq->pSelect->pOrderBy==0
168882169377
){
168883169378
pWInfo->revMask |= MASKBIT(ii);
168884169379
}
168885169380
}
168886169381
}
@@ -169366,19 +169861,19 @@
169366169861
*/
169367169862
assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
169368169863
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
169369169864
int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
169370169865
int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
169371
- assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
169866
+ assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
169372169867
if( bOnerow || (
169373169868
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
169374
- && !IsVirtual(pTabList->a[0].pTab)
169869
+ && !IsVirtual(pTabList->a[0].pSTab)
169375169870
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
169376169871
&& OptimizationEnabled(db, SQLITE_OnePass)
169377169872
)){
169378169873
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
169379
- if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
169874
+ if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
169380169875
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
169381169876
bFordelete = OPFLAG_FORDELETE;
169382169877
}
169383169878
pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
169384169879
}
@@ -169392,11 +169887,11 @@
169392169887
Table *pTab; /* Table to open */
169393169888
int iDb; /* Index of database containing table/index */
169394169889
SrcItem *pTabItem;
169395169890
169396169891
pTabItem = &pTabList->a[pLevel->iFrom];
169397
- pTab = pTabItem->pTab;
169892
+ pTab = pTabItem->pSTab;
169398169893
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
169399169894
pLoop = pLevel->pWLoop;
169400169895
if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
169401169896
/* Do nothing */
169402169897
}else
@@ -169463,11 +169958,11 @@
169463169958
/* This is one term of an OR-optimization using the PRIMARY KEY of a
169464169959
** WITHOUT ROWID table. No need for a separate index */
169465169960
iIndexCur = pLevel->iTabCur;
169466169961
op = 0;
169467169962
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){
169468
- Index *pJ = pTabItem->pTab->pIndex;
169963
+ Index *pJ = pTabItem->pSTab->pIndex;
169469169964
iIndexCur = iAuxArg;
169470169965
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
169471169966
while( ALWAYS(pJ) && pJ!=pIx ){
169472169967
iIndexCur++;
169473169968
pJ = pJ->pNext;
@@ -169530,11 +170025,11 @@
169530170025
pRJ->iMatch = pParse->nTab++;
169531170026
pRJ->regBloom = ++pParse->nMem;
169532170027
sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
169533170028
pRJ->regReturn = ++pParse->nMem;
169534170029
sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
169535
- assert( pTab==pTabItem->pTab );
170030
+ assert( pTab==pTabItem->pSTab );
169536170031
if( HasRowid(pTab) ){
169537170032
KeyInfo *pInfo;
169538170033
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
169539170034
pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
169540170035
if( pInfo ){
@@ -169569,17 +170064,22 @@
169569170064
if( pParse->nErr ) goto whereBeginError;
169570170065
pLevel = &pWInfo->a[ii];
169571170066
wsFlags = pLevel->pWLoop->wsFlags;
169572170067
pSrc = &pTabList->a[pLevel->iFrom];
169573170068
if( pSrc->fg.isMaterialized ){
169574
- if( pSrc->fg.isCorrelated ){
169575
- sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
170069
+ Subquery *pSubq;
170070
+ int iOnce = 0;
170071
+ assert( pSrc->fg.isSubquery );
170072
+ pSubq = pSrc->u4.pSubq;
170073
+ if( pSrc->fg.isCorrelated==0 ){
170074
+ iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
169576170075
}else{
169577
- int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
169578
- sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
169579
- sqlite3VdbeJumpHere(v, iOnce);
170076
+ iOnce = 0;
169580170077
}
170078
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
170079
+ VdbeComment((v, "materialize %!S", pSrc));
170080
+ if( iOnce ) sqlite3VdbeJumpHere(v, iOnce);
169581170081
}
169582170082
assert( pTabList == pWInfo->pTabList );
169583170083
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
169584170084
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
169585170085
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -169788,13 +170288,14 @@
169788170288
if( (ws & WHERE_IDX_ONLY)==0 ){
169789170289
SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
169790170290
assert( pLevel->iTabCur==pSrc->iCursor );
169791170291
if( pSrc->fg.viaCoroutine ){
169792170292
int m, n;
169793
- n = pSrc->regResult;
169794
- assert( pSrc->pTab!=0 );
169795
- m = pSrc->pTab->nCol;
170293
+ assert( pSrc->fg.isSubquery );
170294
+ n = pSrc->u4.pSubq->regResult;
170295
+ assert( pSrc->pSTab!=0 );
170296
+ m = pSrc->pSTab->nCol;
169796170297
sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
169797170298
}
169798170299
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
169799170300
}
169800170301
if( (ws & WHERE_INDEXED)
@@ -169814,20 +170315,20 @@
169814170315
sqlite3VdbeGoto(v, pLevel->addrFirst);
169815170316
}
169816170317
sqlite3VdbeJumpHere(v, addr);
169817170318
}
169818170319
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
169819
- pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
170320
+ pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
169820170321
}
169821170322
169822170323
assert( pWInfo->nLevel<=pTabList->nSrc );
169823170324
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
169824170325
int k, last;
169825170326
VdbeOp *pOp, *pLastOp;
169826170327
Index *pIdx = 0;
169827170328
SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
169828
- Table *pTab = pTabItem->pTab;
170329
+ Table *pTab = pTabItem->pSTab;
169829170330
assert( pTab!=0 );
169830170331
pLoop = pLevel->pWLoop;
169831170332
169832170333
/* Do RIGHT JOIN processing. Generate code that will output the
169833170334
** unmatched rows of the right operand of the RIGHT JOIN with
@@ -169842,13 +170343,14 @@
169842170343
** the co-routine into OP_Copy of result contained in a register.
169843170344
** OP_Rowid becomes OP_Null.
169844170345
*/
169845170346
if( pTabItem->fg.viaCoroutine ){
169846170347
testcase( pParse->db->mallocFailed );
169847
- assert( pTabItem->regResult>=0 );
170348
+ assert( pTabItem->fg.isSubquery );
170349
+ assert( pTabItem->u4.pSubq->regResult>=0 );
169848170350
translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
169849
- pTabItem->regResult, 0);
170351
+ pTabItem->u4.pSubq->regResult, 0);
169850170352
continue;
169851170353
}
169852170354
169853170355
/* If this scan uses an index, make VDBE code substitutions to read data
169854170356
** from the index instead of from the table where possible. In some cases
@@ -171054,13 +171556,14 @@
171054171556
p->selId, p));
171055171557
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
171056171558
assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
171057171559
** of sqlite3DbMallocRawNN() called from
171058171560
** sqlite3SrcListAppend() */
171059
- if( p->pSrc ){
171561
+ if( p->pSrc==0 ){
171562
+ sqlite3SelectDelete(db, pSub);
171563
+ }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
171060171564
Table *pTab2;
171061
- p->pSrc->a[0].pSelect = pSub;
171062171565
p->pSrc->a[0].fg.isCorrelated = 1;
171063171566
sqlite3SrcListAssignCursors(pParse, p->pSrc);
171064171567
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
171065171568
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
171066171569
pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -171070,20 +171573,18 @@
171070171573
** the correct error message regardless. */
171071171574
rc = SQLITE_NOMEM;
171072171575
}else{
171073171576
memcpy(pTab, pTab2, sizeof(Table));
171074171577
pTab->tabFlags |= TF_Ephemeral;
171075
- p->pSrc->a[0].pTab = pTab;
171578
+ p->pSrc->a[0].pSTab = pTab;
171076171579
pTab = pTab2;
171077171580
memset(&w, 0, sizeof(w));
171078171581
w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
171079171582
w.xSelectCallback = sqlite3WalkerDepthIncrease;
171080171583
w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
171081171584
sqlite3WalkSelect(&w, pSub);
171082171585
}
171083
- }else{
171084
- sqlite3SelectDelete(db, pSub);
171085171586
}
171086171587
if( db->mallocFailed ) rc = SQLITE_NOMEM;
171087171588
171088171589
/* Defer deleting the temporary table pTab because if an error occurred,
171089171590
** there could still be references to that table embedded in the
@@ -171366,14 +171867,19 @@
171366171867
** This is called by code in select.c before it calls sqlite3WhereBegin()
171367171868
** to begin iterating through the sub-query results. It is used to allocate
171368171869
** and initialize registers and cursors used by sqlite3WindowCodeStep().
171369171870
*/
171370171871
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
171371
- int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
171372
- Window *pMWin = pSelect->pWin;
171373171872
Window *pWin;
171374
- Vdbe *v = sqlite3GetVdbe(pParse);
171873
+ int nEphExpr;
171874
+ Window *pMWin;
171875
+ Vdbe *v;
171876
+
171877
+ assert( pSelect->pSrc->a[0].fg.isSubquery );
171878
+ nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
171879
+ pMWin = pSelect->pWin;
171880
+ v = sqlite3GetVdbe(pParse);
171375171881
171376171882
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
171377171883
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
171378171884
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
171379171885
sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
@@ -172766,11 +173272,11 @@
172766173272
Window *pMWin = p->pWin;
172767173273
ExprList *pOrderBy = pMWin->pOrderBy;
172768173274
Vdbe *v = sqlite3GetVdbe(pParse);
172769173275
int csrWrite; /* Cursor used to write to eph. table */
172770173276
int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
172771
- int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
173277
+ int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */
172772173278
int iInput; /* To iterate through sub cols */
172773173279
int addrNe; /* Address of OP_Ne */
172774173280
int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
172775173281
int addrInteger = 0; /* Address of OP_Integer */
172776173282
int addrEmpty; /* Address of OP_Rewind in flush: */
@@ -177217,24 +177723,33 @@
177217177723
}else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
177218177724
yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
177219177725
if( yymsp[-5].minor.yy203 ){
177220177726
SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
177221177727
SrcItem *pOld = yymsp[-3].minor.yy203->a;
177728
+ assert( pOld->fg.fixedSchema==0 );
177222177729
pNew->zName = pOld->zName;
177223
- pNew->zDatabase = pOld->zDatabase;
177224
- pNew->pSelect = pOld->pSelect;
177225
- if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
177226
- pNew->fg.isNestedFrom = 1;
177730
+ assert( pOld->fg.fixedSchema==0 );
177731
+ if( pOld->fg.isSubquery ){
177732
+ pNew->fg.isSubquery = 1;
177733
+ pNew->u4.pSubq = pOld->u4.pSubq;
177734
+ pOld->u4.pSubq = 0;
177735
+ pOld->fg.isSubquery = 0;
177736
+ assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
177737
+ if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
177738
+ pNew->fg.isNestedFrom = 1;
177739
+ }
177740
+ }else{
177741
+ pNew->u4.zDatabase = pOld->u4.zDatabase;
177742
+ pOld->u4.zDatabase = 0;
177227177743
}
177228177744
if( pOld->fg.isTabFunc ){
177229177745
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
177230177746
pOld->u1.pFuncArg = 0;
177231177747
pOld->fg.isTabFunc = 0;
177232177748
pNew->fg.isTabFunc = 1;
177233177749
}
177234
- pOld->zName = pOld->zDatabase = 0;
177235
- pOld->pSelect = 0;
177750
+ pOld->zName = 0;
177236177751
}
177237177752
sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
177238177753
}else{
177239177754
Select *pSubquery;
177240177755
sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
@@ -182324,11 +182839,12 @@
182324182839
}
182325182840
182326182841
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
182327182842
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
182328182843
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
182329
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
182844
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|
182845
+ SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1);
182330182846
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
182331182847
182332182848
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
182333182849
** the meaning is inverted. So flip the bit. */
182334182850
assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
@@ -184790,10 +185306,22 @@
184790185306
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
184791185307
sqlite3 *db = va_arg(ap, sqlite3*);
184792185308
db->dbOptFlags = va_arg(ap, u32);
184793185309
break;
184794185310
}
185311
+
185312
+ /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N)
185313
+ **
185314
+ ** Write the current optimization settings into *N. A zero bit means that
185315
+ ** the optimization is on, and a 1 bit means that the optimization is off.
185316
+ */
185317
+ case SQLITE_TESTCTRL_GETOPT: {
185318
+ sqlite3 *db = va_arg(ap, sqlite3*);
185319
+ int *pN = va_arg(ap, int*);
185320
+ *pN = db->dbOptFlags;
185321
+ break;
185322
+ }
184795185323
184796185324
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
184797185325
**
184798185326
** If parameter onoff is 1, subsequent calls to localtime() fail.
184799185327
** If 2, then invoke xAlt() instead of localtime(). If 0, normal
@@ -224464,10 +224992,11 @@
224464224992
)
224465224993
){
224466224994
pIdxInfo->orderByConsumed = 1;
224467224995
pIdxInfo->idxNum |= 0x08;
224468224996
}
224997
+ pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX;
224469224998
224470224999
return SQLITE_OK;
224471225000
}
224472225001
224473225002
/*
@@ -232374,13 +232903,36 @@
232374232903
** It is the output of the tokenizer module. For tokendata=1 tables, this
232375232904
** includes any embedded 0x00 and trailing data.
232376232905
**
232377232906
** This API can be quite slow if used with an FTS5 table created with the
232378232907
** "detail=none" or "detail=column" option.
232908
+**
232909
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
232910
+** If parameter iCol is less than zero, or greater than or equal to the
232911
+** number of columns in the table, SQLITE_RANGE is returned.
232912
+**
232913
+** Otherwise, this function attempts to retrieve the locale associated
232914
+** with column iCol of the current row. Usually, there is no associated
232915
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
232916
+** to NULL and 0, respectively. However, if the fts5_locale() function
232917
+** was used to associate a locale with the value when it was inserted
232918
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
232919
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
232920
+** is set to the size in bytes of the buffer, not including the
232921
+** nul-terminator.
232922
+**
232923
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
232924
+** SQLite error code is returned. The final value of the output parameters
232925
+** is undefined in this case.
232926
+**
232927
+** xTokenize_v2:
232928
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
232929
+** API is the same as the xTokenize() API, except that it allows a tokenizer
232930
+** locale to be specified.
232379232931
*/
232380232932
struct Fts5ExtensionApi {
232381
- int iVersion; /* Currently always set to 3 */
232933
+ int iVersion; /* Currently always set to 4 */
232382232934
232383232935
void *(*xUserData)(Fts5Context*);
232384232936
232385232937
int (*xColumnCount)(Fts5Context*);
232386232938
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -232418,10 +232970,19 @@
232418232970
int (*xQueryToken)(Fts5Context*,
232419232971
int iPhrase, int iToken,
232420232972
const char **ppToken, int *pnToken
232421232973
);
232422232974
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
232975
+
232976
+ /* Below this point are iVersion>=4 only */
232977
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
232978
+ int (*xTokenize_v2)(Fts5Context*,
232979
+ const char *pText, int nText, /* Text to tokenize */
232980
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
232981
+ void *pCtx, /* Context passed to xToken() */
232982
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
232983
+ );
232423232984
};
232424232985
232425232986
/*
232426232987
** CUSTOM AUXILIARY FUNCTIONS
232427232988
*************************************************************************/
@@ -232430,19 +232991,20 @@
232430232991
** CUSTOM TOKENIZERS
232431232992
**
232432232993
** Applications may also register custom tokenizer types. A tokenizer
232433232994
** is registered by providing fts5 with a populated instance of the
232434232995
** following structure. All structure methods must be defined, setting
232996
+**
232435232997
** any member of the fts5_tokenizer struct to NULL leads to undefined
232436232998
** behaviour. The structure methods are expected to function as follows:
232437232999
**
232438233000
** xCreate:
232439233001
** This function is used to allocate and initialize a tokenizer instance.
232440233002
** A tokenizer instance is required to actually tokenize text.
232441233003
**
232442233004
** The first argument passed to this function is a copy of the (void*)
232443
-** pointer provided by the application when the fts5_tokenizer object
233005
+** pointer provided by the application when the fts5_tokenizer_v2 object
232444233006
** was registered with FTS5 (the third argument to xCreateTokenizer()).
232445233007
** The second and third arguments are an array of nul-terminated strings
232446233008
** containing the tokenizer arguments, if any, specified following the
232447233009
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
232448233010
** to create the FTS5 table.
@@ -232462,11 +233024,11 @@
232462233024
** This function is expected to tokenize the nText byte string indicated
232463233025
** by argument pText. pText may or may not be nul-terminated. The first
232464233026
** argument passed to this function is a pointer to an Fts5Tokenizer object
232465233027
** returned by an earlier call to xCreate().
232466233028
**
232467
-** The second argument indicates the reason that FTS5 is requesting
233029
+** The third argument indicates the reason that FTS5 is requesting
232468233030
** tokenization of the supplied text. This is always one of the following
232469233031
** four values:
232470233032
**
232471233033
** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
232472233034
** or removed from the FTS table. The tokenizer is being invoked to
@@ -232485,10 +233047,17 @@
232485233047
** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
232486233048
** satisfy an fts5_api.xTokenize() request made by an auxiliary
232487233049
** function. Or an fts5_api.xColumnSize() request made by the same
232488233050
** on a columnsize=0 database.
232489233051
** </ul>
233052
+**
233053
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
233054
+** nLocale - are a pointer to a buffer containing the locale to use for
233055
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
233056
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
233057
+** which case nLocale is always 0) to indicate that the tokenizer should
233058
+** use its default locale.
232490233059
**
232491233060
** For each token in the input string, the supplied callback xToken() must
232492233061
** be invoked. The first argument to it should be a copy of the pointer
232493233062
** passed as the second argument to xTokenize(). The third and fourth
232494233063
** arguments are a pointer to a buffer containing the token text, and the
@@ -232508,10 +233077,34 @@
232508233077
** immediately return a copy of the xToken() return value. Or, if the
232509233078
** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
232510233079
** if an error occurs with the xTokenize() implementation itself, it
232511233080
** may abandon the tokenization and return any error code other than
232512233081
** SQLITE_OK or SQLITE_DONE.
233082
+**
233083
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
233084
+** then the xTokenize() method has two additional arguments - pLocale
233085
+** and nLocale. These specify the locale that the tokenizer should use
233086
+** for the current request. If pLocale and nLocale are both 0, then the
233087
+** tokenizer should use its default locale. Otherwise, pLocale points to
233088
+** an nLocale byte buffer containing the name of the locale to use as utf-8
233089
+** text. pLocale is not nul-terminated.
233090
+**
233091
+** FTS5_TOKENIZER
233092
+**
233093
+** There is also an fts5_tokenizer object. This is an older, deprecated,
233094
+** version of fts5_tokenizer_v2. It is similar except that:
233095
+**
233096
+** <ul>
233097
+** <li> There is no "iVersion" field, and
233098
+** <li> The xTokenize() method does not take a locale argument.
233099
+** </ul>
233100
+**
233101
+** Legacy fts5_tokenizer tokenizers must be registered using the
233102
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
233103
+**
233104
+** Tokenizer implementations registered using either API may be retrieved
233105
+** using both xFindTokenizer() and xFindTokenizer_v2().
232513233106
**
232514233107
** SYNONYM SUPPORT
232515233108
**
232516233109
** Custom tokenizers may also support synonyms. Consider a case in which a
232517233110
** user wishes to query for a phrase such as "first place". Using the
@@ -232617,10 +233210,37 @@
232617233210
** provide synonyms when tokenizing document text (method (3)) or query
232618233211
** text (method (2)), not both. Doing so will not cause any errors, but is
232619233212
** inefficient.
232620233213
*/
232621233214
typedef struct Fts5Tokenizer Fts5Tokenizer;
233215
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
233216
+struct fts5_tokenizer_v2 {
233217
+ int iVersion; /* Currently always 2 */
233218
+
233219
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
233220
+ void (*xDelete)(Fts5Tokenizer*);
233221
+ int (*xTokenize)(Fts5Tokenizer*,
233222
+ void *pCtx,
233223
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
233224
+ const char *pText, int nText,
233225
+ const char *pLocale, int nLocale,
233226
+ int (*xToken)(
233227
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
233228
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
233229
+ const char *pToken, /* Pointer to buffer containing token */
233230
+ int nToken, /* Size of token in bytes */
233231
+ int iStart, /* Byte offset of token within input text */
233232
+ int iEnd /* Byte offset of end of token within input text */
233233
+ )
233234
+ );
233235
+};
233236
+
233237
+/*
233238
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
233239
+** implementations. The following type is included for legacy applications
233240
+** that still use it.
233241
+*/
232622233242
typedef struct fts5_tokenizer fts5_tokenizer;
232623233243
struct fts5_tokenizer {
232624233244
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
232625233245
void (*xDelete)(Fts5Tokenizer*);
232626233246
int (*xTokenize)(Fts5Tokenizer*,
@@ -232635,10 +233255,11 @@
232635233255
int iStart, /* Byte offset of token within input text */
232636233256
int iEnd /* Byte offset of end of token within input text */
232637233257
)
232638233258
);
232639233259
};
233260
+
232640233261
232641233262
/* Flags that may be passed as the third argument to xTokenize() */
232642233263
#define FTS5_TOKENIZE_QUERY 0x0001
232643233264
#define FTS5_TOKENIZE_PREFIX 0x0002
232644233265
#define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -232655,11 +233276,11 @@
232655233276
/*************************************************************************
232656233277
** FTS5 EXTENSION REGISTRATION API
232657233278
*/
232658233279
typedef struct fts5_api fts5_api;
232659233280
struct fts5_api {
232660
- int iVersion; /* Currently always set to 2 */
233281
+ int iVersion; /* Currently always set to 3 */
232661233282
232662233283
/* Create a new tokenizer */
232663233284
int (*xCreateTokenizer)(
232664233285
fts5_api *pApi,
232665233286
const char *zName,
@@ -232682,10 +233303,29 @@
232682233303
const char *zName,
232683233304
void *pUserData,
232684233305
fts5_extension_function xFunction,
232685233306
void (*xDestroy)(void*)
232686233307
);
233308
+
233309
+ /* APIs below this point are only available if iVersion>=3 */
233310
+
233311
+ /* Create a new tokenizer */
233312
+ int (*xCreateTokenizer_v2)(
233313
+ fts5_api *pApi,
233314
+ const char *zName,
233315
+ void *pUserData,
233316
+ fts5_tokenizer_v2 *pTokenizer,
233317
+ void (*xDestroy)(void*)
233318
+ );
233319
+
233320
+ /* Find an existing tokenizer */
233321
+ int (*xFindTokenizer_v2)(
233322
+ fts5_api *pApi,
233323
+ const char *zName,
233324
+ void **ppUserData,
233325
+ fts5_tokenizer_v2 **ppTokenizer
233326
+ );
232687233327
};
232688233328
232689233329
/*
232690233330
** END OF REGISTRATION API
232691233331
*************************************************************************/
@@ -232858,14 +233498,17 @@
232858233498
typedef struct Fts5Config Fts5Config;
232859233499
typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
232860233500
232861233501
struct Fts5TokenizerConfig {
232862233502
Fts5Tokenizer *pTok;
232863
- fts5_tokenizer *pTokApi;
233503
+ fts5_tokenizer_v2 *pApi2;
233504
+ fts5_tokenizer *pApi1;
232864233505
const char **azArg;
232865233506
int nArg;
232866233507
int ePattern; /* FTS_PATTERN_XXX constant */
233508
+ const char *pLocale; /* Current locale to use */
233509
+ int nLocale; /* Size of pLocale in bytes */
232867233510
};
232868233511
232869233512
/*
232870233513
** An instance of the following structure encodes all information that can
232871233514
** be gleaned from the CREATE VIRTUAL TABLE statement.
@@ -232902,10 +233545,12 @@
232902233545
** This is only used for debugging. If set to false, any prefix indexes
232903233546
** are ignored. This value is configured using:
232904233547
**
232905233548
** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
232906233549
**
233550
+** bLocale:
233551
+** Set to true if locale=1 was specified when the table was created.
232907233552
*/
232908233553
struct Fts5Config {
232909233554
sqlite3 *db; /* Database handle */
232910233555
Fts5Global *pGlobal; /* Global fts5 object for handle db */
232911233556
char *zDb; /* Database holding FTS index (e.g. "main") */
@@ -232919,14 +233564,16 @@
232919233564
int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
232920233565
char *zContent; /* content table */
232921233566
char *zContentRowid; /* "content_rowid=" option value */
232922233567
int bColumnsize; /* "columnsize=" option value (dflt==1) */
232923233568
int bTokendata; /* "tokendata=" option value (dflt==0) */
233569
+ int bLocale; /* "locale=" option value (dflt==0) */
232924233570
int eDetail; /* FTS5_DETAIL_XXX value */
232925233571
char *zContentExprlist;
232926233572
Fts5TokenizerConfig t;
232927233573
int bLock; /* True when table is preparing statement */
233574
+
232928233575
232929233576
/* Values loaded from the %_config table */
232930233577
int iVersion; /* fts5 file format 'version' */
232931233578
int iCookie; /* Incremented when %_config is modified */
232932233579
int pgsz; /* Approximate page size used in %_data */
@@ -232988,10 +233635,12 @@
232988233635
/* Set the value of a single config attribute */
232989233636
static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
232990233637
232991233638
static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
232992233639
233640
+static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
233641
+
232993233642
/*
232994233643
** End of interface to code in fts5_config.c.
232995233644
**************************************************************************/
232996233645
232997233646
/**************************************************************************
@@ -233032,11 +233681,11 @@
233032233681
233033233682
/* Write and decode big-endian 32-bit integer values */
233034233683
static void sqlite3Fts5Put32(u8*, int);
233035233684
static int sqlite3Fts5Get32(const u8*);
233036233685
233037
-#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
233686
+#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
233038233687
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
233039233688
233040233689
typedef struct Fts5PoslistReader Fts5PoslistReader;
233041233690
struct Fts5PoslistReader {
233042233691
/* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
@@ -233323,10 +233972,21 @@
233323233972
233324233973
static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
233325233974
233326233975
static int sqlite3Fts5FlushToDisk(Fts5Table*);
233327233976
233977
+static int sqlite3Fts5ExtractText(
233978
+ Fts5Config *pConfig,
233979
+ sqlite3_value *pVal, /* Value to extract text from */
233980
+ int bContent, /* Loaded from content table */
233981
+ int *pbResetTokenizer, /* OUT: True if ClearLocale() required */
233982
+ const char **ppText, /* OUT: Pointer to text buffer */
233983
+ int *pnText /* OUT: Size of (*ppText) in bytes */
233984
+);
233985
+
233986
+static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
233987
+
233328233988
/*
233329233989
** End of interface to code in fts5.c.
233330233990
**************************************************************************/
233331233991
233332233992
/**************************************************************************
@@ -233402,11 +234062,11 @@
233402234062
static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
233403234063
233404234064
static int sqlite3Fts5DropAll(Fts5Config*);
233405234065
static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
233406234066
233407
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
234067
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
233408234068
static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
233409234069
static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
233410234070
233411234071
static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
233412234072
@@ -233428,10 +234088,13 @@
233428234088
static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
233429234089
static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
233430234090
static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
233431234091
static int sqlite3Fts5StorageReset(Fts5Storage *p);
233432234092
234093
+static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
234094
+static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
234095
+
233433234096
/*
233434234097
** End of interface to code in fts5_storage.c.
233435234098
**************************************************************************/
233436234099
233437234100
@@ -235357,10 +236020,11 @@
235357236020
p->iOff = iEndOff;
235358236021
}
235359236022
235360236023
return rc;
235361236024
}
236025
+
235362236026
235363236027
/*
235364236028
** Implementation of highlight() function.
235365236029
*/
235366236030
static void fts5HighlightFunction(
@@ -235388,16 +236052,23 @@
235388236052
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
235389236053
if( rc==SQLITE_RANGE ){
235390236054
sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
235391236055
rc = SQLITE_OK;
235392236056
}else if( ctx.zIn ){
236057
+ const char *pLoc = 0; /* Locale of column iCol */
236058
+ int nLoc = 0; /* Size of pLoc in bytes */
235393236059
if( rc==SQLITE_OK ){
235394236060
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
235395236061
}
235396236062
235397236063
if( rc==SQLITE_OK ){
235398
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
236064
+ rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
236065
+ }
236066
+ if( rc==SQLITE_OK ){
236067
+ rc = pApi->xTokenize_v2(
236068
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
236069
+ );
235399236070
}
235400236071
if( ctx.bOpen ){
235401236072
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
235402236073
}
235403236074
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
@@ -235590,19 +236261,23 @@
235590236261
}
235591236262
235592236263
memset(&sFinder, 0, sizeof(Fts5SFinder));
235593236264
for(i=0; i<nCol; i++){
235594236265
if( iCol<0 || iCol==i ){
236266
+ const char *pLoc = 0; /* Locale of column iCol */
236267
+ int nLoc = 0; /* Size of pLoc in bytes */
235595236268
int nDoc;
235596236269
int nDocsize;
235597236270
int ii;
235598236271
sFinder.iPos = 0;
235599236272
sFinder.nFirst = 0;
235600236273
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
235601236274
if( rc!=SQLITE_OK ) break;
235602
- rc = pApi->xTokenize(pFts,
235603
- sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
236275
+ rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
236276
+ if( rc!=SQLITE_OK ) break;
236277
+ rc = pApi->xTokenize_v2(pFts,
236278
+ sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
235604236279
);
235605236280
if( rc!=SQLITE_OK ) break;
235606236281
rc = pApi->xColumnSize(pFts, i, &nDocsize);
235607236282
if( rc!=SQLITE_OK ) break;
235608236283
@@ -235656,10 +236331,13 @@
235656236331
}
235657236332
if( rc==SQLITE_OK && nColSize==0 ){
235658236333
rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
235659236334
}
235660236335
if( ctx.zIn ){
236336
+ const char *pLoc = 0; /* Locale of column iBestCol */
236337
+ int nLoc = 0; /* Bytes in pLoc */
236338
+
235661236339
if( rc==SQLITE_OK ){
235662236340
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
235663236341
}
235664236342
235665236343
ctx.iRangeStart = iBestStart;
@@ -235674,11 +236352,16 @@
235674236352
while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
235675236353
rc = fts5CInstIterNext(&ctx.iter);
235676236354
}
235677236355
235678236356
if( rc==SQLITE_OK ){
235679
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
236357
+ rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
236358
+ }
236359
+ if( rc==SQLITE_OK ){
236360
+ rc = pApi->xTokenize_v2(
236361
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
236362
+ );
235680236363
}
235681236364
if( ctx.bOpen ){
235682236365
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
235683236366
}
235684236367
if( ctx.iRangeEnd>=(nColSize-1) ){
@@ -235857,21 +236540,69 @@
235857236540
sqlite3_result_double(pCtx, -1.0 * score);
235858236541
}else{
235859236542
sqlite3_result_error_code(pCtx, rc);
235860236543
}
235861236544
}
236545
+
236546
+/*
236547
+** Implementation of fts5_get_locale() function.
236548
+*/
236549
+static void fts5GetLocaleFunction(
236550
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
236551
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
236552
+ sqlite3_context *pCtx, /* Context for returning result/error */
236553
+ int nVal, /* Number of values in apVal[] array */
236554
+ sqlite3_value **apVal /* Array of trailing arguments */
236555
+){
236556
+ int iCol = 0;
236557
+ int eType = 0;
236558
+ int rc = SQLITE_OK;
236559
+ const char *zLocale = 0;
236560
+ int nLocale = 0;
236561
+
236562
+ /* xColumnLocale() must be available */
236563
+ assert( pApi->iVersion>=4 );
236564
+
236565
+ if( nVal!=1 ){
236566
+ const char *z = "wrong number of arguments to function fts5_get_locale()";
236567
+ sqlite3_result_error(pCtx, z, -1);
236568
+ return;
236569
+ }
236570
+
236571
+ eType = sqlite3_value_numeric_type(apVal[0]);
236572
+ if( eType!=SQLITE_INTEGER ){
236573
+ const char *z = "non-integer argument passed to function fts5_get_locale()";
236574
+ sqlite3_result_error(pCtx, z, -1);
236575
+ return;
236576
+ }
236577
+
236578
+ iCol = sqlite3_value_int(apVal[0]);
236579
+ if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
236580
+ sqlite3_result_error_code(pCtx, SQLITE_RANGE);
236581
+ return;
236582
+ }
236583
+
236584
+ rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
236585
+ if( rc!=SQLITE_OK ){
236586
+ sqlite3_result_error_code(pCtx, rc);
236587
+ return;
236588
+ }
236589
+
236590
+ sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
236591
+}
235862236592
235863236593
static int sqlite3Fts5AuxInit(fts5_api *pApi){
235864236594
struct Builtin {
235865236595
const char *zFunc; /* Function name (nul-terminated) */
235866236596
void *pUserData; /* User-data pointer */
235867236597
fts5_extension_function xFunc;/* Callback function */
235868236598
void (*xDestroy)(void*); /* Destructor function */
235869236599
} aBuiltin [] = {
235870
- { "snippet", 0, fts5SnippetFunction, 0 },
235871
- { "highlight", 0, fts5HighlightFunction, 0 },
235872
- { "bm25", 0, fts5Bm25Function, 0 },
236600
+ { "snippet", 0, fts5SnippetFunction, 0 },
236601
+ { "highlight", 0, fts5HighlightFunction, 0 },
236602
+ { "bm25", 0, fts5Bm25Function, 0 },
236603
+ { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
235873236604
};
235874236605
int rc = SQLITE_OK; /* Return code */
235875236606
int i; /* To iterate through builtin functions */
235876236607
235877236608
for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
@@ -236677,10 +237408,20 @@
236677237408
}else{
236678237409
pConfig->bColumnsize = (zArg[0]=='1');
236679237410
}
236680237411
return rc;
236681237412
}
237413
+
237414
+ if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
237415
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
237416
+ *pzErr = sqlite3_mprintf("malformed locale=... directive");
237417
+ rc = SQLITE_ERROR;
237418
+ }else{
237419
+ pConfig->bLocale = (zArg[0]=='1');
237420
+ }
237421
+ return rc;
237422
+ }
236682237423
236683237424
if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
236684237425
const Fts5Enum aDetail[] = {
236685237426
{ "none", FTS5_DETAIL_NONE },
236686237427
{ "full", FTS5_DETAIL_FULL },
@@ -236967,11 +237708,15 @@
236967237708
*/
236968237709
static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
236969237710
if( pConfig ){
236970237711
int i;
236971237712
if( pConfig->t.pTok ){
236972
- pConfig->t.pTokApi->xDelete(pConfig->t.pTok);
237713
+ if( pConfig->t.pApi1 ){
237714
+ pConfig->t.pApi1->xDelete(pConfig->t.pTok);
237715
+ }else{
237716
+ pConfig->t.pApi2->xDelete(pConfig->t.pTok);
237717
+ }
236973237718
}
236974237719
sqlite3_free((char*)pConfig->t.azArg);
236975237720
sqlite3_free(pConfig->zDb);
236976237721
sqlite3_free(pConfig->zName);
236977237722
for(i=0; i<pConfig->nCol; i++){
@@ -237050,13 +237795,19 @@
237050237795
if( pText ){
237051237796
if( pConfig->t.pTok==0 ){
237052237797
rc = sqlite3Fts5LoadTokenizer(pConfig);
237053237798
}
237054237799
if( rc==SQLITE_OK ){
237055
- rc = pConfig->t.pTokApi->xTokenize(
237056
- pConfig->t.pTok, pCtx, flags, pText, nText, xToken
237057
- );
237800
+ if( pConfig->t.pApi1 ){
237801
+ rc = pConfig->t.pApi1->xTokenize(
237802
+ pConfig->t.pTok, pCtx, flags, pText, nText, xToken
237803
+ );
237804
+ }else{
237805
+ rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
237806
+ pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
237807
+ );
237808
+ }
237058237809
}
237059237810
}
237060237811
return rc;
237061237812
}
237062237813
@@ -237309,26 +238060,46 @@
237309238060
if( rc==SQLITE_OK
237310238061
&& iVersion!=FTS5_CURRENT_VERSION
237311238062
&& iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
237312238063
){
237313238064
rc = SQLITE_ERROR;
237314
- if( pConfig->pzErrmsg ){
237315
- assert( 0==*pConfig->pzErrmsg );
237316
- *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
237317
- "(found %d, expected %d or %d) - run 'rebuild'",
237318
- iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
237319
- );
237320
- }
238065
+ sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
238066
+ "(found %d, expected %d or %d) - run 'rebuild'",
238067
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
238068
+ );
237321238069
}else{
237322238070
pConfig->iVersion = iVersion;
237323238071
}
237324238072
237325238073
if( rc==SQLITE_OK ){
237326238074
pConfig->iCookie = iCookie;
237327238075
}
237328238076
return rc;
237329238077
}
238078
+
238079
+/*
238080
+** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer
238081
+** containing the error message created using printf() style formatting
238082
+** string zFmt and its trailing arguments.
238083
+*/
238084
+static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
238085
+ va_list ap; /* ... printf arguments */
238086
+ char *zMsg = 0;
238087
+
238088
+ va_start(ap, zFmt);
238089
+ zMsg = sqlite3_vmprintf(zFmt, ap);
238090
+ if( pConfig->pzErrmsg ){
238091
+ assert( *pConfig->pzErrmsg==0 );
238092
+ *pConfig->pzErrmsg = zMsg;
238093
+ }else{
238094
+ sqlite3_free(zMsg);
238095
+ }
238096
+
238097
+ va_end(ap);
238098
+}
238099
+
238100
+
237330238101
237331238102
/*
237332238103
** 2014 May 31
237333238104
**
237334238105
** The author disclaims copyright to this source code. In place of
@@ -237614,15 +238385,16 @@
237614238385
t = fts5ExprGetToken(&sParse, &z, &token);
237615238386
sqlite3Fts5Parser(pEngine, t, token, &sParse);
237616238387
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
237617238388
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
237618238389
238390
+ assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
237619238391
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
237620238392
237621238393
/* If the LHS of the MATCH expression was a user column, apply the
237622238394
** implicit column-filter. */
237623
- if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
238395
+ if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
237624238396
int n = sizeof(Fts5Colset);
237625238397
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
237626238398
if( pColset ){
237627238399
pColset->nCol = 1;
237628238400
pColset->aiCol[0] = iCol;
@@ -237635,19 +238407,11 @@
237635238407
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
237636238408
if( pNew==0 ){
237637238409
sParse.rc = SQLITE_NOMEM;
237638238410
sqlite3Fts5ParseNodeFree(sParse.pExpr);
237639238411
}else{
237640
- if( !sParse.pExpr ){
237641
- const int nByte = sizeof(Fts5ExprNode);
237642
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
237643
- if( pNew->pRoot ){
237644
- pNew->pRoot->bEof = 1;
237645
- }
237646
- }else{
237647
- pNew->pRoot = sParse.pExpr;
237648
- }
238412
+ pNew->pRoot = sParse.pExpr;
237649238413
pNew->pIndex = 0;
237650238414
pNew->pConfig = pConfig;
237651238415
pNew->apExprPhrase = sParse.apPhrase;
237652238416
pNew->nPhrase = sParse.nPhrase;
237653238417
pNew->bDesc = 0;
@@ -238461,11 +239225,11 @@
238461239225
pNode->bEof = 1;
238462239226
return rc;
238463239227
}
238464239228
}else{
238465239229
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
238466
- if( pIter->iRowid==iLast || pIter->bEof ) continue;
239230
+ if( pIter->iRowid==iLast ) continue;
238467239231
bMatch = 0;
238468239232
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
238469239233
return rc;
238470239234
}
238471239235
}
@@ -238983,13 +239747,10 @@
238983239747
){
238984239748
const int SZALLOC = 8;
238985239749
Fts5ExprNearset *pRet = 0;
238986239750
238987239751
if( pParse->rc==SQLITE_OK ){
238988
- if( pPhrase==0 ){
238989
- return pNear;
238990
- }
238991239752
if( pNear==0 ){
238992239753
sqlite3_int64 nByte;
238993239754
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
238994239755
pRet = sqlite3_malloc64(nByte);
238995239756
if( pRet==0 ){
@@ -243382,11 +244143,11 @@
243382244143
iOff = 4;
243383244144
}
243384244145
243385244146
if( iOff<pIter->iEndofDoclist ){
243386244147
/* Next entry is on the current page */
243387
- i64 iDelta;
244148
+ u64 iDelta;
243388244149
iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
243389244150
pIter->iLeafOffset = iOff;
243390244151
pIter->iRowid += iDelta;
243391244152
}else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
243392244153
if( pIter->pSeg ){
@@ -250372,15 +251133,32 @@
250372251133
250373251134
/*
250374251135
** Each tokenizer module registered with the FTS5 module is represented
250375251136
** by an object of the following type. All such objects are stored as part
250376251137
** of the Fts5Global.pTok list.
251138
+**
251139
+** bV2Native:
251140
+** True if the tokenizer was registered using xCreateTokenizer_v2(), false
251141
+** for xCreateTokenizer(). If this variable is true, then x2 is populated
251142
+** with the routines as supplied by the caller and x1 contains synthesized
251143
+** wrapper routines. In this case the user-data pointer passed to
251144
+** x1.xCreate should be a pointer to the Fts5TokenizerModule structure,
251145
+** not a copy of pUserData.
251146
+**
251147
+** Of course, if bV2Native is false, then x1 contains the real routines and
251148
+** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule
251149
+** object should be passed to x2.xCreate.
251150
+**
251151
+** The synthesized wrapper routines are necessary for xFindTokenizer(_v2)
251152
+** calls.
250377251153
*/
250378251154
struct Fts5TokenizerModule {
250379251155
char *zName; /* Name of tokenizer */
250380251156
void *pUserData; /* User pointer passed to xCreate() */
250381
- fts5_tokenizer x; /* Tokenizer functions */
251157
+ int bV2Native; /* True if v2 native tokenizer */
251158
+ fts5_tokenizer x1; /* Tokenizer functions */
251159
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
250382251160
void (*xDestroy)(void*); /* Destructor function */
250383251161
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
250384251162
};
250385251163
250386251164
struct Fts5FullTable {
@@ -250464,11 +251242,11 @@
250464251242
250465251243
/* Auxiliary data storage */
250466251244
Fts5Auxiliary *pAux; /* Currently executing extension function */
250467251245
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
250468251246
250469
- /* Cache used by auxiliary functions xInst() and xInstCount() */
251247
+ /* Cache used by auxiliary API functions xInst() and xInstCount() */
250470251248
Fts5PoslistReader *aInstIter; /* One for each phrase */
250471251249
int nInstAlloc; /* Size of aInst[] array (entries / 3) */
250472251250
int nInstCount; /* Number of phrase instances */
250473251251
int *aInst; /* 3 integers per phrase instance */
250474251252
};
@@ -250499,10 +251277,16 @@
250499251277
#define FTS5CSR_REQUIRE_POSLIST 0x40
250500251278
250501251279
#define BitFlagAllTest(x,y) (((x) & (y))==(y))
250502251280
#define BitFlagTest(x,y) (((x) & (y))!=0)
250503251281
251282
+/*
251283
+** The subtype value and header bytes used by fts5_locale().
251284
+*/
251285
+#define FTS5_LOCALE_SUBTYPE ((unsigned int)'L')
251286
+#define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB"
251287
+
250504251288
250505251289
/*
250506251290
** Macros to Set(), Clear() and Test() cursor flags.
250507251291
*/
250508251292
#define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -250673,12 +251457,11 @@
250673251457
rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
250674251458
}
250675251459
250676251460
/* Load the initial configuration */
250677251461
if( rc==SQLITE_OK ){
250678
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
250679
- sqlite3Fts5IndexRollback(pTab->p.pIndex);
251462
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1);
250680251463
}
250681251464
250682251465
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
250683251466
rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
250684251467
}
@@ -250876,11 +251659,11 @@
250876251659
}else{
250877251660
if( iCol==nCol+1 ){
250878251661
if( bSeenRank ) continue;
250879251662
idxStr[iIdxStr++] = 'r';
250880251663
bSeenRank = 1;
250881
- }else if( iCol>=0 ){
251664
+ }else{
250882251665
nSeenMatch++;
250883251666
idxStr[iIdxStr++] = 'M';
250884251667
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
250885251668
idxStr += strlen(&idxStr[iIdxStr]);
250886251669
assert( idxStr[iIdxStr]=='\0' );
@@ -251262,11 +252045,11 @@
251262252045
rc = SQLITE_NOMEM;
251263252046
}else{
251264252047
rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
251265252048
SQLITE_PREPARE_PERSISTENT, &pRet, 0);
251266252049
if( rc!=SQLITE_OK ){
251267
- *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
252050
+ sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db));
251268252051
}
251269252052
sqlite3_free(zSql);
251270252053
}
251271252054
251272252055
va_end(ap);
@@ -251497,10 +252280,192 @@
251497252280
sqlite3_free(p->p.base.zErrMsg);
251498252281
p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
251499252282
va_end(ap);
251500252283
}
251501252284
252285
+/*
252286
+** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
252287
+** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
252288
+** valid until after the final call to sqlite3Fts5Tokenize() that will use
252289
+** the locale.
252290
+*/
252291
+static void fts5SetLocale(
252292
+ Fts5Config *pConfig,
252293
+ const char *zLocale,
252294
+ int nLocale
252295
+){
252296
+ Fts5TokenizerConfig *pT = &pConfig->t;
252297
+ pT->pLocale = zLocale;
252298
+ pT->nLocale = nLocale;
252299
+}
252300
+
252301
+/*
252302
+** Clear any locale configured by an earlier call to fts5SetLocale() or
252303
+** sqlite3Fts5ExtractText().
252304
+*/
252305
+static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
252306
+ fts5SetLocale(pConfig, 0, 0);
252307
+}
252308
+
252309
+/*
252310
+** This function is used to extract utf-8 text from an sqlite3_value. This
252311
+** is usually done in order to tokenize it. For example, when:
252312
+**
252313
+** * a value is written to an fts5 table,
252314
+** * a value is deleted from an FTS5_CONTENT_NORMAL table,
252315
+** * a value containing a query expression is passed to xFilter()
252316
+**
252317
+** and so on.
252318
+**
252319
+** This function handles 2 cases:
252320
+**
252321
+** 1) Ordinary values. The text can be extracted from these using
252322
+** sqlite3_value_text().
252323
+**
252324
+** 2) Combination text/locale blobs created by fts5_locale(). There
252325
+** are several cases for these:
252326
+**
252327
+** * Blobs tagged with FTS5_LOCALE_SUBTYPE.
252328
+** * Blobs read from the content table of a locale=1 external-content
252329
+** table, and
252330
+** * Blobs read from the content table of a locale=1 regular
252331
+** content table.
252332
+**
252333
+** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER
252334
+** header. It is an error if a blob with the subtype or a blob read
252335
+** from the content table of an external content table does not have
252336
+** the required header. A blob read from the content table of a regular
252337
+** locale=1 table does not have the header. This is to save space.
252338
+**
252339
+** If successful, SQLITE_OK is returned and output parameters (*ppText)
252340
+** and (*pnText) are set to point to a buffer containing the extracted utf-8
252341
+** text and its length in bytes, respectively. The buffer is not
252342
+** nul-terminated. It has the same lifetime as the sqlite3_value object
252343
+** from which it is extracted.
252344
+**
252345
+** Parameter bContent must be true if the value was read from an indexed
252346
+** column (i.e. not UNINDEXED) of the on disk content.
252347
+**
252348
+** If pbResetTokenizer is not NULL and if case (2) is used, then
252349
+** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls
252350
+** use the locale. In this case (*pbResetTokenizer) is set to true before
252351
+** returning, to indicate that the caller must call sqlite3Fts5ClearLocale()
252352
+** to clear the locale after tokenizing the text.
252353
+*/
252354
+static int sqlite3Fts5ExtractText(
252355
+ Fts5Config *pConfig,
252356
+ sqlite3_value *pVal, /* Value to extract text from */
252357
+ int bContent, /* True if indexed table content */
252358
+ int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */
252359
+ const char **ppText, /* OUT: Pointer to text buffer */
252360
+ int *pnText /* OUT: Size of (*ppText) in bytes */
252361
+){
252362
+ const char *pText = 0;
252363
+ int nText = 0;
252364
+ int rc = SQLITE_OK;
252365
+ int bDecodeBlob = 0;
252366
+
252367
+ assert( pbResetTokenizer==0 || *pbResetTokenizer==0 );
252368
+ assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE );
252369
+ assert( bContent==0 || sqlite3_value_subtype(pVal)==0 );
252370
+
252371
+ if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
252372
+ if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE
252373
+ || (bContent && pConfig->bLocale)
252374
+ ){
252375
+ bDecodeBlob = 1;
252376
+ }
252377
+ }
252378
+
252379
+ if( bDecodeBlob ){
252380
+ const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
252381
+ const u8 *pBlob = sqlite3_value_blob(pVal);
252382
+ int nBlob = sqlite3_value_bytes(pVal);
252383
+
252384
+ /* Unless this blob was read from the %_content table of an
252385
+ ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale()
252386
+ ** header. Check for this. If it is not found, return an error. */
252387
+ if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){
252388
+ if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
252389
+ rc = SQLITE_ERROR;
252390
+ }else{
252391
+ pBlob += 4;
252392
+ nBlob -= 4;
252393
+ }
252394
+ }
252395
+
252396
+ if( rc==SQLITE_OK ){
252397
+ int nLocale = 0;
252398
+
252399
+ for(nLocale=0; nLocale<nBlob; nLocale++){
252400
+ if( pBlob[nLocale]==0x00 ) break;
252401
+ }
252402
+ if( nLocale==nBlob || nLocale==0 ){
252403
+ rc = SQLITE_ERROR;
252404
+ }else{
252405
+ pText = (const char*)&pBlob[nLocale+1];
252406
+ nText = nBlob-nLocale-1;
252407
+
252408
+ if( pbResetTokenizer ){
252409
+ fts5SetLocale(pConfig, (const char*)pBlob, nLocale);
252410
+ *pbResetTokenizer = 1;
252411
+ }
252412
+ }
252413
+ }
252414
+
252415
+ }else{
252416
+ pText = (const char*)sqlite3_value_text(pVal);
252417
+ nText = sqlite3_value_bytes(pVal);
252418
+ }
252419
+
252420
+ *ppText = pText;
252421
+ *pnText = nText;
252422
+ return rc;
252423
+}
252424
+
252425
+/*
252426
+** Argument pVal is the text of a full-text search expression. It may or
252427
+** may not have been wrapped by fts5_locale(). This function extracts
252428
+** the text of the expression, and sets output variable (*pzText) to
252429
+** point to a nul-terminated buffer containing the expression.
252430
+**
252431
+** If pVal was an fts5_locale() value, then fts5SetLocale() is called to
252432
+** set the tokenizer to use the specified locale.
252433
+**
252434
+** If output variable (*pbFreeAndReset) is set to true, then the caller
252435
+** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
252436
+** locale, and (b) call sqlite3_free() to free (*pzText).
252437
+*/
252438
+static int fts5ExtractExprText(
252439
+ Fts5Config *pConfig, /* Fts5 configuration */
252440
+ sqlite3_value *pVal, /* Value to extract expression text from */
252441
+ char **pzText, /* OUT: nul-terminated buffer of text */
252442
+ int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
252443
+){
252444
+ const char *zText = 0;
252445
+ int nText = 0;
252446
+ int rc = SQLITE_OK;
252447
+ int bReset = 0;
252448
+
252449
+ *pbFreeAndReset = 0;
252450
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, &bReset, &zText, &nText);
252451
+ if( rc==SQLITE_OK ){
252452
+ if( bReset ){
252453
+ *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, zText);
252454
+ if( rc!=SQLITE_OK ){
252455
+ sqlite3Fts5ClearLocale(pConfig);
252456
+ }else{
252457
+ *pbFreeAndReset = 1;
252458
+ }
252459
+ }else{
252460
+ *pzText = (char*)zText;
252461
+ }
252462
+ }
252463
+
252464
+ return rc;
252465
+}
252466
+
251502252467
251503252468
/*
251504252469
** This is the xFilter interface for the virtual table. See
251505252470
** the virtual table xFilter method documentation for additional
251506252471
** information.
@@ -251532,17 +252497,11 @@
251532252497
char **pzErrmsg = pConfig->pzErrmsg;
251533252498
int i;
251534252499
int iIdxStr = 0;
251535252500
Fts5Expr *pExpr = 0;
251536252501
251537
- if( pConfig->bLock ){
251538
- pTab->p.base.zErrMsg = sqlite3_mprintf(
251539
- "recursively defined fts5 content table"
251540
- );
251541
- return SQLITE_ERROR;
251542
- }
251543
-
252502
+ assert( pConfig->bLock==0 );
251544252503
if( pCsr->ePlan ){
251545252504
fts5FreeCursorComponents(pCsr);
251546252505
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
251547252506
}
251548252507
@@ -251562,12 +252521,18 @@
251562252521
switch( idxStr[iIdxStr++] ){
251563252522
case 'r':
251564252523
pRank = apVal[i];
251565252524
break;
251566252525
case 'M': {
251567
- const char *zText = (const char*)sqlite3_value_text(apVal[i]);
252526
+ char *zText = 0;
252527
+ int bFreeAndReset = 0;
252528
+ int bInternal = 0;
252529
+
252530
+ rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
252531
+ if( rc!=SQLITE_OK ) goto filter_out;
251568252532
if( zText==0 ) zText = "";
252533
+
251569252534
iCol = 0;
251570252535
do{
251571252536
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
251572252537
iIdxStr++;
251573252538
}while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
@@ -251575,21 +252540,27 @@
251575252540
if( zText[0]=='*' ){
251576252541
/* The user has issued a query of the form "MATCH '*...'". This
251577252542
** indicates that the MATCH expression is not a full text query,
251578252543
** but a request for an internal parameter. */
251579252544
rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
251580
- goto filter_out;
252545
+ bInternal = 1;
251581252546
}else{
251582252547
char **pzErr = &pTab->p.base.zErrMsg;
251583252548
rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
251584252549
if( rc==SQLITE_OK ){
251585252550
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
251586252551
pExpr = 0;
251587252552
}
251588
- if( rc!=SQLITE_OK ) goto filter_out;
251589252553
}
251590252554
252555
+ if( bFreeAndReset ){
252556
+ sqlite3_free(zText);
252557
+ sqlite3Fts5ClearLocale(pConfig);
252558
+ }
252559
+
252560
+ if( bInternal || rc!=SQLITE_OK ) goto filter_out;
252561
+
251591252562
break;
251592252563
}
251593252564
case 'L':
251594252565
case 'G': {
251595252566
int bGlob = (idxStr[iIdxStr-1]=='G');
@@ -251893,11 +252864,11 @@
251893252864
){
251894252865
int rc = SQLITE_OK;
251895252866
int eType1 = sqlite3_value_type(apVal[1]);
251896252867
if( eType1==SQLITE_INTEGER ){
251897252868
sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
251898
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
252869
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
251899252870
}
251900252871
return rc;
251901252872
}
251902252873
251903252874
static void fts5StorageInsert(
@@ -252017,59 +252988,81 @@
252017252988
}
252018252989
252019252990
/* DELETE */
252020252991
else if( nArg==1 ){
252021252992
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
252022
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
252993
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
252023252994
bUpdateOrDelete = 1;
252024252995
}
252025252996
252026252997
/* INSERT or UPDATE */
252027252998
else{
252028252999
int eType1 = sqlite3_value_numeric_type(apVal[1]);
252029253000
252030
- if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
252031
- rc = SQLITE_MISMATCH;
253001
+ /* Ensure that no fts5_locale() values are written to locale=0 tables.
253002
+ ** And that no blobs except fts5_locale() blobs are written to indexed
253003
+ ** (i.e. not UNINDEXED) columns of locale=1 tables. */
253004
+ int ii;
253005
+ for(ii=0; ii<pConfig->nCol; ii++){
253006
+ if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){
253007
+ int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE);
253008
+ if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0)
253009
+ || (pConfig->bLocale==0 && bSub)
253010
+ ){
253011
+ if( pConfig->bLocale==0 ){
253012
+ fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
253013
+ }
253014
+ rc = SQLITE_MISMATCH;
253015
+ goto update_out;
253016
+ }
253017
+ }
252032253018
}
252033253019
252034
- else if( eType0!=SQLITE_INTEGER ){
253020
+ if( eType0!=SQLITE_INTEGER ){
252035253021
/* An INSERT statement. If the conflict-mode is REPLACE, first remove
252036253022
** the current entry (if any). */
252037253023
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
252038253024
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
252039
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
253025
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
252040253026
bUpdateOrDelete = 1;
252041253027
}
252042253028
fts5StorageInsert(&rc, pTab, apVal, pRowid);
252043253029
}
252044253030
252045253031
/* UPDATE */
252046253032
else{
252047253033
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
252048253034
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
252049
- if( eType1==SQLITE_INTEGER && iOld!=iNew ){
253035
+ if( eType1!=SQLITE_INTEGER ){
253036
+ rc = SQLITE_MISMATCH;
253037
+ }else if( iOld!=iNew ){
252050253038
if( eConflict==SQLITE_REPLACE ){
252051
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
253039
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
252052253040
if( rc==SQLITE_OK ){
252053
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
253041
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
252054253042
}
252055253043
fts5StorageInsert(&rc, pTab, apVal, pRowid);
252056253044
}else{
252057
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
253045
+ rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld);
253046
+ if( rc==SQLITE_OK ){
253047
+ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid);
253048
+ }
252058253049
if( rc==SQLITE_OK ){
252059
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
253050
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
252060253051
}
252061253052
if( rc==SQLITE_OK ){
252062253053
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
252063253054
}
252064253055
}
252065253056
}else{
252066
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
253057
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
252067253058
fts5StorageInsert(&rc, pTab, apVal, pRowid);
252068253059
}
252069253060
bUpdateOrDelete = 1;
253061
+ sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage);
252070253062
}
253063
+
252071253064
}
252072253065
}
252073253066
252074253067
if( rc==SQLITE_OK
252075253068
&& bUpdateOrDelete
@@ -252082,10 +253075,11 @@
252082253075
if( rc==SQLITE_OK ){
252083253076
pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
252084253077
}
252085253078
}
252086253079
253080
+ update_out:
252087253081
pTab->p.pConfig->pzErrmsg = 0;
252088253082
return rc;
252089253083
}
252090253084
252091253085
/*
@@ -252103,13 +253097,15 @@
252103253097
252104253098
/*
252105253099
** Implementation of xBegin() method.
252106253100
*/
252107253101
static int fts5BeginMethod(sqlite3_vtab *pVtab){
252108
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
252109
- fts5NewTransaction((Fts5FullTable*)pVtab);
252110
- return SQLITE_OK;
253102
+ int rc = fts5NewTransaction((Fts5FullTable*)pVtab);
253103
+ if( rc==SQLITE_OK ){
253104
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
253105
+ }
253106
+ return rc;
252111253107
}
252112253108
252113253109
/*
252114253110
** Implementation of xCommit() method. This is a no-op. The contents of
252115253111
** the pending-terms hash-table have already been flushed into the database
@@ -252159,21 +253155,44 @@
252159253155
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252160253156
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
252161253157
return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
252162253158
}
252163253159
253160
+/*
253161
+** Implementation of xTokenize_v2() API.
253162
+*/
253163
+static int fts5ApiTokenize_v2(
253164
+ Fts5Context *pCtx,
253165
+ const char *pText, int nText,
253166
+ const char *pLoc, int nLoc,
253167
+ void *pUserData,
253168
+ int (*xToken)(void*, int, const char*, int, int, int)
253169
+){
253170
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253171
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253172
+ int rc = SQLITE_OK;
253173
+
253174
+ fts5SetLocale(pTab->pConfig, pLoc, nLoc);
253175
+ rc = sqlite3Fts5Tokenize(pTab->pConfig,
253176
+ FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
253177
+ );
253178
+ fts5SetLocale(pTab->pConfig, 0, 0);
253179
+
253180
+ return rc;
253181
+}
253182
+
253183
+/*
253184
+** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0
253185
+** passed as the locale.
253186
+*/
252164253187
static int fts5ApiTokenize(
252165253188
Fts5Context *pCtx,
252166253189
const char *pText, int nText,
252167253190
void *pUserData,
252168253191
int (*xToken)(void*, int, const char*, int, int, int)
252169253192
){
252170
- Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252171
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
252172
- return sqlite3Fts5Tokenize(
252173
- pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
252174
- );
253193
+ return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken);
252175253194
}
252176253195
252177253196
static int fts5ApiPhraseCount(Fts5Context *pCtx){
252178253197
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252179253198
return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
@@ -252191,53 +253210,76 @@
252191253210
int *pn
252192253211
){
252193253212
int rc = SQLITE_OK;
252194253213
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252195253214
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253215
+
253216
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
252196253217
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
252197253218
rc = SQLITE_RANGE;
252198
- }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
252199
- || pCsr->ePlan==FTS5_PLAN_SPECIAL
252200
- ){
253219
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){
252201253220
*pz = 0;
252202253221
*pn = 0;
252203253222
}else{
252204253223
rc = fts5SeekCursor(pCsr, 0);
252205253224
if( rc==SQLITE_OK ){
252206
- *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
252207
- *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
253225
+ Fts5Config *pConfig = pTab->pConfig;
253226
+ int bContent = (pConfig->abUnindexed[iCol]==0);
253227
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253228
+ sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn);
252208253229
}
252209253230
}
252210253231
return rc;
252211253232
}
252212253233
253234
+/*
253235
+** This is called by various API functions - xInst, xPhraseFirst,
253236
+** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase
253237
+** of the current row. This function works for both detail=full tables (in
253238
+** which case the position-list was read from the fts index) or for other
253239
+** detail= modes if the row content is available.
253240
+*/
252213253241
static int fts5CsrPoslist(
252214
- Fts5Cursor *pCsr,
252215
- int iPhrase,
252216
- const u8 **pa,
252217
- int *pn
253242
+ Fts5Cursor *pCsr, /* Fts5 cursor object */
253243
+ int iPhrase, /* Phrase to find position list for */
253244
+ const u8 **pa, /* OUT: Pointer to position list buffer */
253245
+ int *pn /* OUT: Size of (*pa) in bytes */
252218253246
){
252219253247
Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
252220253248
int rc = SQLITE_OK;
252221253249
int bLive = (pCsr->pSorter==0);
252222253250
252223253251
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
252224253252
rc = SQLITE_RANGE;
253253
+ }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
253254
+ && pConfig->eContent==FTS5_CONTENT_NONE
253255
+ ){
253256
+ *pa = 0;
253257
+ *pn = 0;
253258
+ return SQLITE_OK;
252225253259
}else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
252226253260
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
252227253261
Fts5PoslistPopulator *aPopulator;
252228253262
int i;
253263
+
252229253264
aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
252230253265
if( aPopulator==0 ) rc = SQLITE_NOMEM;
253266
+ if( rc==SQLITE_OK ){
253267
+ rc = fts5SeekCursor(pCsr, 0);
253268
+ }
252231253269
for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
252232
- int n; const char *z;
252233
- rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
253270
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253271
+ const char *z = 0;
253272
+ int n = 0;
253273
+ int bReset = 0;
253274
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
252234253275
if( rc==SQLITE_OK ){
252235253276
rc = sqlite3Fts5ExprPopulatePoslists(
252236253277
pConfig, pCsr->pExpr, aPopulator, i, z, n
252237253278
);
252238253279
}
253280
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
252239253281
}
252240253282
sqlite3_free(aPopulator);
252241253283
252242253284
if( pCsr->pSorter ){
252243253285
sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -252257,11 +253299,10 @@
252257253299
}
252258253300
}else{
252259253301
*pa = 0;
252260253302
*pn = 0;
252261253303
}
252262
-
252263253304
252264253305
return rc;
252265253306
}
252266253307
252267253308
/*
@@ -252327,11 +253368,12 @@
252327253368
252328253369
aInst = &pCsr->aInst[3 * (nInst-1)];
252329253370
aInst[0] = iBest;
252330253371
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
252331253372
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
252332
- if( aInst[1]<0 || aInst[1]>=nCol ){
253373
+ assert( aInst[1]>=0 );
253374
+ if( aInst[1]>=nCol ){
252333253375
rc = FTS5_CORRUPT;
252334253376
break;
252335253377
}
252336253378
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
252337253379
}
@@ -252414,20 +253456,25 @@
252414253456
pCsr->aColumnSize[i] = -1;
252415253457
}
252416253458
}
252417253459
}else{
252418253460
int i;
253461
+ rc = fts5SeekCursor(pCsr, 0);
252419253462
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
252420253463
if( pConfig->abUnindexed[i]==0 ){
252421
- const char *z; int n;
252422
- void *p = (void*)(&pCsr->aColumnSize[i]);
253464
+ const char *z = 0;
253465
+ int n = 0;
253466
+ int bReset = 0;
253467
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253468
+
252423253469
pCsr->aColumnSize[i] = 0;
252424
- rc = fts5ApiColumnText(pCtx, i, &z, &n);
253470
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
252425253471
if( rc==SQLITE_OK ){
252426
- rc = sqlite3Fts5Tokenize(
252427
- pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
253472
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
253473
+ z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
252428253474
);
253475
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
252429253476
}
252430253477
}
252431253478
}
252432253479
}
252433253480
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
@@ -252669,13 +253716,76 @@
252669253716
252670253717
252671253718
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
252672253719
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
252673253720
);
253721
+
253722
+/*
253723
+** The xColumnLocale() API.
253724
+*/
253725
+static int fts5ApiColumnLocale(
253726
+ Fts5Context *pCtx,
253727
+ int iCol,
253728
+ const char **pzLocale,
253729
+ int *pnLocale
253730
+){
253731
+ int rc = SQLITE_OK;
253732
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253733
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
253734
+
253735
+ *pzLocale = 0;
253736
+ *pnLocale = 0;
253737
+
253738
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253739
+ if( iCol<0 || iCol>=pConfig->nCol ){
253740
+ rc = SQLITE_RANGE;
253741
+ }else if(
253742
+ pConfig->abUnindexed[iCol]==0
253743
+ && pConfig->eContent!=FTS5_CONTENT_NONE
253744
+ && pConfig->bLocale
253745
+ ){
253746
+ rc = fts5SeekCursor(pCsr, 0);
253747
+ if( rc==SQLITE_OK ){
253748
+ /* Load the value into pVal. pVal is a locale/text pair iff:
253749
+ **
253750
+ ** 1) It is an SQLITE_BLOB, and
253751
+ ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the
253752
+ ** value was loaded from an FTS5_CONTENT_NORMAL table, and
253753
+ ** 3) It does not begin with an 0x00 byte.
253754
+ */
253755
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253756
+ if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
253757
+ const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
253758
+ int nBlob = sqlite3_value_bytes(pVal);
253759
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
253760
+ const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
253761
+ if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
253762
+ rc = SQLITE_ERROR;
253763
+ }
253764
+ pBlob += 4;
253765
+ nBlob -= 4;
253766
+ }
253767
+ if( rc==SQLITE_OK ){
253768
+ int nLocale = 0;
253769
+ for(nLocale=0; nLocale<nBlob && pBlob[nLocale]!=0x00; nLocale++);
253770
+ if( nLocale==nBlob || nLocale==0 ){
253771
+ rc = SQLITE_ERROR;
253772
+ }else{
253773
+ /* A locale/text pair */
253774
+ *pzLocale = (const char*)pBlob;
253775
+ *pnLocale = nLocale;
253776
+ }
253777
+ }
253778
+ }
253779
+ }
253780
+ }
253781
+
253782
+ return rc;
253783
+}
252674253784
252675253785
static const Fts5ExtensionApi sFts5Api = {
252676
- 3, /* iVersion */
253786
+ 4, /* iVersion */
252677253787
fts5ApiUserData,
252678253788
fts5ApiColumnCount,
252679253789
fts5ApiRowCount,
252680253790
fts5ApiColumnTotalSize,
252681253791
fts5ApiTokenize,
@@ -252692,11 +253802,13 @@
252692253802
fts5ApiPhraseFirst,
252693253803
fts5ApiPhraseNext,
252694253804
fts5ApiPhraseFirstColumn,
252695253805
fts5ApiPhraseNextColumn,
252696253806
fts5ApiQueryToken,
252697
- fts5ApiInstToken
253807
+ fts5ApiInstToken,
253808
+ fts5ApiColumnLocale,
253809
+ fts5ApiTokenize_v2
252698253810
};
252699253811
252700253812
/*
252701253813
** Implementation of API function xQueryPhrase().
252702253814
*/
@@ -252743,10 +253855,11 @@
252743253855
sqlite3_context *context,
252744253856
int argc,
252745253857
sqlite3_value **argv
252746253858
){
252747253859
assert( pCsr->pAux==0 );
253860
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
252748253861
pCsr->pAux = pAux;
252749253862
pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
252750253863
pCsr->pAux = 0;
252751253864
}
252752253865
@@ -252755,10 +253868,25 @@
252755253868
for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
252756253869
if( pCsr->iCsrId==iCsrId ) break;
252757253870
}
252758253871
return pCsr;
252759253872
}
253873
+
253874
+/*
253875
+** Parameter zFmt is a printf() style formatting string. This function
253876
+** formats it using the trailing arguments and returns the result as
253877
+** an error message to the context passed as the first argument.
253878
+*/
253879
+static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){
253880
+ char *zErr = 0;
253881
+ va_list ap;
253882
+ va_start(ap, zFmt);
253883
+ zErr = sqlite3_vmprintf(zFmt, ap);
253884
+ sqlite3_result_error(pCtx, zErr, -1);
253885
+ sqlite3_free(zErr);
253886
+ va_end(ap);
253887
+}
252760253888
252761253889
static void fts5ApiCallback(
252762253890
sqlite3_context *context,
252763253891
int argc,
252764253892
sqlite3_value **argv
@@ -252771,14 +253899,12 @@
252771253899
assert( argc>=1 );
252772253900
pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
252773253901
iCsrId = sqlite3_value_int64(argv[0]);
252774253902
252775253903
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
252776
- if( pCsr==0 || pCsr->ePlan==0 ){
252777
- char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
252778
- sqlite3_result_error(context, zErr, -1);
252779
- sqlite3_free(zErr);
253904
+ if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){
253905
+ fts5ResultError(context, "no such cursor: %lld", iCsrId);
252780253906
}else{
252781253907
sqlite3_vtab *pTab = pCsr->base.pVtab;
252782253908
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
252783253909
sqlite3_free(pTab->zErrMsg);
252784253910
pTab->zErrMsg = 0;
@@ -252867,10 +253993,61 @@
252867253993
}
252868253994
252869253995
sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
252870253996
return rc;
252871253997
}
253998
+
253999
+/*
254000
+** Value pVal was read from column iCol of the FTS5 table. This function
254001
+** returns it to the owner of pCtx via a call to an sqlite3_result_xxx()
254002
+** function. This function deals with the same cases as
254003
+** sqlite3Fts5ExtractText():
254004
+**
254005
+** 1) Ordinary values. These can be returned using sqlite3_result_value().
254006
+**
254007
+** 2) Blobs from fts5_locale(). The text is extracted from these and
254008
+** returned via sqlite3_result_text(). The locale is discarded.
254009
+*/
254010
+static void fts5ExtractValueFromColumn(
254011
+ sqlite3_context *pCtx,
254012
+ Fts5Config *pConfig,
254013
+ int iCol,
254014
+ sqlite3_value *pVal
254015
+){
254016
+ assert( pConfig->eContent!=FTS5_CONTENT_NONE );
254017
+
254018
+ if( pConfig->bLocale
254019
+ && sqlite3_value_type(pVal)==SQLITE_BLOB
254020
+ && pConfig->abUnindexed[iCol]==0
254021
+ ){
254022
+ const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
254023
+ const u8 *pBlob = sqlite3_value_blob(pVal);
254024
+ int nBlob = sqlite3_value_bytes(pVal);
254025
+ int ii;
254026
+
254027
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
254028
+ if( nBlob<SZHDR || memcmp(pBlob, FTS5_LOCALE_HEADER, SZHDR) ){
254029
+ sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254030
+ return;
254031
+ }else{
254032
+ pBlob += 4;
254033
+ nBlob -= 4;
254034
+ }
254035
+ }
254036
+
254037
+ for(ii=0; ii<nBlob && pBlob[ii]; ii++);
254038
+ if( ii==0 || ii==nBlob ){
254039
+ sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254040
+ }else{
254041
+ const char *pText = (const char*)&pBlob[ii+1];
254042
+ sqlite3_result_text(pCtx, pText, nBlob-ii-1, SQLITE_TRANSIENT);
254043
+ }
254044
+ return;
254045
+ }
254046
+
254047
+ sqlite3_result_value(pCtx, pVal);
254048
+}
252872254049
252873254050
/*
252874254051
** This is the xColumn method, called by SQLite to request a value from
252875254052
** the row that the supplied cursor currently points to.
252876254053
*/
@@ -252897,12 +254074,12 @@
252897254074
** as the table. Return the cursor integer id number. This value is only
252898254075
** useful in that it may be passed as the first argument to an FTS5
252899254076
** auxiliary function. */
252900254077
sqlite3_result_int64(pCtx, pCsr->iCsrId);
252901254078
}else if( iCol==pConfig->nCol+1 ){
252902
-
252903254079
/* The value of the "rank" column. */
254080
+
252904254081
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
252905254082
fts5PoslistBlob(pCtx, pCsr);
252906254083
}else if(
252907254084
pCsr->ePlan==FTS5_PLAN_MATCH
252908254085
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
@@ -252909,24 +254086,31 @@
252909254086
){
252910254087
if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
252911254088
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
252912254089
}
252913254090
}
252914
- }else if( !fts5IsContentless(pTab) ){
252915
- pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
252916
- rc = fts5SeekCursor(pCsr, 1);
252917
- if( rc==SQLITE_OK ){
252918
- sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
252919
- }
252920
- pConfig->pzErrmsg = 0;
252921
- }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
252922
- char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
252923
- "columns on fts5 contentless-delete table: %s", pConfig->zName
252924
- );
252925
- sqlite3_result_error(pCtx, zErr, -1);
252926
- sqlite3_free(zErr);
252927
- }
254091
+ }else{
254092
+ /* A column created by the user containing values. */
254093
+ int bNochange = sqlite3_vtab_nochange(pCtx);
254094
+
254095
+ if( fts5IsContentless(pTab) ){
254096
+ if( bNochange && pConfig->bContentlessDelete ){
254097
+ fts5ResultError(pCtx, "cannot UPDATE a subset of "
254098
+ "columns on fts5 contentless-delete table: %s", pConfig->zName
254099
+ );
254100
+ }
254101
+ }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
254102
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
254103
+ rc = fts5SeekCursor(pCsr, 1);
254104
+ if( rc==SQLITE_OK ){
254105
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
254106
+ fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal);
254107
+ }
254108
+ pConfig->pzErrmsg = 0;
254109
+ }
254110
+ }
254111
+
252928254112
return rc;
252929254113
}
252930254114
252931254115
252932254116
/*
@@ -253060,53 +254244,216 @@
253060254244
}
253061254245
}
253062254246
253063254247
return rc;
253064254248
}
254249
+
254250
+/*
254251
+** This function is used by xCreateTokenizer_v2() and xCreateTokenizer().
254252
+** It allocates and partially populates a new Fts5TokenizerModule object.
254253
+** The new object is already linked into the Fts5Global context before
254254
+** returning.
254255
+**
254256
+** If successful, SQLITE_OK is returned and a pointer to the new
254257
+** Fts5TokenizerModule object returned via output parameter (*ppNew). All
254258
+** that is required is for the caller to fill in the methods in
254259
+** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native
254260
+** as appropriate.
254261
+**
254262
+** If an error occurs, an SQLite error code is returned and the final value
254263
+** of (*ppNew) undefined.
254264
+*/
254265
+static int fts5NewTokenizerModule(
254266
+ Fts5Global *pGlobal, /* Global context (one per db handle) */
254267
+ const char *zName, /* Name of new function */
254268
+ void *pUserData, /* User data for aux. function */
254269
+ void(*xDestroy)(void*), /* Destructor for pUserData */
254270
+ Fts5TokenizerModule **ppNew
254271
+){
254272
+ int rc = SQLITE_OK;
254273
+ Fts5TokenizerModule *pNew;
254274
+ sqlite3_int64 nName; /* Size of zName and its \0 terminator */
254275
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
254276
+
254277
+ nName = strlen(zName) + 1;
254278
+ nByte = sizeof(Fts5TokenizerModule) + nName;
254279
+ *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte);
254280
+ if( pNew ){
254281
+ pNew->zName = (char*)&pNew[1];
254282
+ memcpy(pNew->zName, zName, nName);
254283
+ pNew->pUserData = pUserData;
254284
+ pNew->xDestroy = xDestroy;
254285
+ pNew->pNext = pGlobal->pTok;
254286
+ pGlobal->pTok = pNew;
254287
+ if( pNew->pNext==0 ){
254288
+ pGlobal->pDfltTok = pNew;
254289
+ }
254290
+ }
254291
+
254292
+ return rc;
254293
+}
254294
+
254295
+/*
254296
+** An instance of this type is used as the Fts5Tokenizer object for
254297
+** wrapper tokenizers - those that provide access to a v1 tokenizer via
254298
+** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer
254299
+** via the fts5_tokenizer API.
254300
+*/
254301
+typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
254302
+struct Fts5VtoVTokenizer {
254303
+ int bV2Native; /* True if v2 native tokenizer */
254304
+ fts5_tokenizer x1; /* Tokenizer functions */
254305
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
254306
+ Fts5Tokenizer *pReal;
254307
+};
254308
+
254309
+/*
254310
+** Create a wrapper tokenizer. The context argument pCtx points to the
254311
+** Fts5TokenizerModule object.
254312
+*/
254313
+static int fts5VtoVCreate(
254314
+ void *pCtx,
254315
+ const char **azArg,
254316
+ int nArg,
254317
+ Fts5Tokenizer **ppOut
254318
+){
254319
+ Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx;
254320
+ Fts5VtoVTokenizer *pNew = 0;
254321
+ int rc = SQLITE_OK;
254322
+
254323
+ pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
254324
+ if( rc==SQLITE_OK ){
254325
+ pNew->x1 = pMod->x1;
254326
+ pNew->x2 = pMod->x2;
254327
+ pNew->bV2Native = pMod->bV2Native;
254328
+ if( pMod->bV2Native ){
254329
+ rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
254330
+ }else{
254331
+ rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
254332
+ }
254333
+ if( rc!=SQLITE_OK ){
254334
+ sqlite3_free(pNew);
254335
+ pNew = 0;
254336
+ }
254337
+ }
254338
+
254339
+ *ppOut = (Fts5Tokenizer*)pNew;
254340
+ return rc;
254341
+}
254342
+
254343
+/*
254344
+** Delete an Fts5VtoVTokenizer wrapper tokenizer.
254345
+*/
254346
+static void fts5VtoVDelete(Fts5Tokenizer *pTok){
254347
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254348
+ if( p ){
254349
+ if( p->bV2Native ){
254350
+ p->x2.xDelete(p->pReal);
254351
+ }else{
254352
+ p->x1.xDelete(p->pReal);
254353
+ }
254354
+ sqlite3_free(p);
254355
+ }
254356
+}
254357
+
254358
+
254359
+/*
254360
+** xTokenizer method for a wrapper tokenizer that offers the v1 interface
254361
+** (no support for locales).
254362
+*/
254363
+static int fts5V1toV2Tokenize(
254364
+ Fts5Tokenizer *pTok,
254365
+ void *pCtx, int flags,
254366
+ const char *pText, int nText,
254367
+ int (*xToken)(void*, int, const char*, int, int, int)
254368
+){
254369
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254370
+ assert( p->bV2Native );
254371
+ return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
254372
+}
254373
+
254374
+/*
254375
+** xTokenizer method for a wrapper tokenizer that offers the v2 interface
254376
+** (with locale support).
254377
+*/
254378
+static int fts5V2toV1Tokenize(
254379
+ Fts5Tokenizer *pTok,
254380
+ void *pCtx, int flags,
254381
+ const char *pText, int nText,
254382
+ const char *pLocale, int nLocale,
254383
+ int (*xToken)(void*, int, const char*, int, int, int)
254384
+){
254385
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254386
+ assert( p->bV2Native==0 );
254387
+ UNUSED_PARAM2(pLocale,nLocale);
254388
+ return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
254389
+}
253065254390
253066254391
/*
253067254392
** Register a new tokenizer. This is the implementation of the
253068
-** fts5_api.xCreateTokenizer() method.
254393
+** fts5_api.xCreateTokenizer_v2() method.
254394
+*/
254395
+static int fts5CreateTokenizer_v2(
254396
+ fts5_api *pApi, /* Global context (one per db handle) */
254397
+ const char *zName, /* Name of new function */
254398
+ void *pUserData, /* User data for aux. function */
254399
+ fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */
254400
+ void(*xDestroy)(void*) /* Destructor for pUserData */
254401
+){
254402
+ Fts5Global *pGlobal = (Fts5Global*)pApi;
254403
+ int rc = SQLITE_OK;
254404
+
254405
+ if( pTokenizer->iVersion>2 ){
254406
+ rc = SQLITE_ERROR;
254407
+ }else{
254408
+ Fts5TokenizerModule *pNew = 0;
254409
+ rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew);
254410
+ if( pNew ){
254411
+ pNew->x2 = *pTokenizer;
254412
+ pNew->bV2Native = 1;
254413
+ pNew->x1.xCreate = fts5VtoVCreate;
254414
+ pNew->x1.xTokenize = fts5V1toV2Tokenize;
254415
+ pNew->x1.xDelete = fts5VtoVDelete;
254416
+ }
254417
+ }
254418
+
254419
+ return rc;
254420
+}
254421
+
254422
+/*
254423
+** The fts5_api.xCreateTokenizer() method.
253069254424
*/
253070254425
static int fts5CreateTokenizer(
253071254426
fts5_api *pApi, /* Global context (one per db handle) */
253072254427
const char *zName, /* Name of new function */
253073254428
void *pUserData, /* User data for aux. function */
253074254429
fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
253075254430
void(*xDestroy)(void*) /* Destructor for pUserData */
253076254431
){
253077
- Fts5Global *pGlobal = (Fts5Global*)pApi;
253078
- Fts5TokenizerModule *pNew;
253079
- sqlite3_int64 nName; /* Size of zName and its \0 terminator */
253080
- sqlite3_int64 nByte; /* Bytes of space to allocate */
254432
+ Fts5TokenizerModule *pNew = 0;
253081254433
int rc = SQLITE_OK;
253082254434
253083
- nName = strlen(zName) + 1;
253084
- nByte = sizeof(Fts5TokenizerModule) + nName;
253085
- pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
254435
+ rc = fts5NewTokenizerModule(
254436
+ (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew
254437
+ );
253086254438
if( pNew ){
253087
- memset(pNew, 0, (size_t)nByte);
253088
- pNew->zName = (char*)&pNew[1];
253089
- memcpy(pNew->zName, zName, nName);
253090
- pNew->pUserData = pUserData;
253091
- pNew->x = *pTokenizer;
253092
- pNew->xDestroy = xDestroy;
253093
- pNew->pNext = pGlobal->pTok;
253094
- pGlobal->pTok = pNew;
253095
- if( pNew->pNext==0 ){
253096
- pGlobal->pDfltTok = pNew;
253097
- }
253098
- }else{
253099
- rc = SQLITE_NOMEM;
253100
- }
253101
-
254439
+ pNew->x1 = *pTokenizer;
254440
+ pNew->x2.xCreate = fts5VtoVCreate;
254441
+ pNew->x2.xTokenize = fts5V2toV1Tokenize;
254442
+ pNew->x2.xDelete = fts5VtoVDelete;
254443
+ }
253102254444
return rc;
253103254445
}
253104254446
254447
+/*
254448
+** Search the global context passed as the first argument for a tokenizer
254449
+** module named zName. If found, return a pointer to the Fts5TokenizerModule
254450
+** object. Otherwise, return NULL.
254451
+*/
253105254452
static Fts5TokenizerModule *fts5LocateTokenizer(
253106
- Fts5Global *pGlobal,
253107
- const char *zName
254453
+ Fts5Global *pGlobal, /* Global (one per db handle) object */
254454
+ const char *zName /* Name of tokenizer module to find */
253108254455
){
253109254456
Fts5TokenizerModule *pMod = 0;
253110254457
253111254458
if( zName==0 ){
253112254459
pMod = pGlobal->pDfltTok;
@@ -253116,10 +254463,40 @@
253116254463
}
253117254464
}
253118254465
253119254466
return pMod;
253120254467
}
254468
+
254469
+/*
254470
+** Find a tokenizer. This is the implementation of the
254471
+** fts5_api.xFindTokenizer_v2() method.
254472
+*/
254473
+static int fts5FindTokenizer_v2(
254474
+ fts5_api *pApi, /* Global context (one per db handle) */
254475
+ const char *zName, /* Name of tokenizer */
254476
+ void **ppUserData,
254477
+ fts5_tokenizer_v2 **ppTokenizer /* Populate this object */
254478
+){
254479
+ int rc = SQLITE_OK;
254480
+ Fts5TokenizerModule *pMod;
254481
+
254482
+ pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
254483
+ if( pMod ){
254484
+ if( pMod->bV2Native ){
254485
+ *ppUserData = pMod->pUserData;
254486
+ }else{
254487
+ *ppUserData = (void*)pMod;
254488
+ }
254489
+ *ppTokenizer = &pMod->x2;
254490
+ }else{
254491
+ *ppTokenizer = 0;
254492
+ *ppUserData = 0;
254493
+ rc = SQLITE_ERROR;
254494
+ }
254495
+
254496
+ return rc;
254497
+}
253121254498
253122254499
/*
253123254500
** Find a tokenizer. This is the implementation of the
253124254501
** fts5_api.xFindTokenizer() method.
253125254502
*/
@@ -253132,70 +254509,79 @@
253132254509
int rc = SQLITE_OK;
253133254510
Fts5TokenizerModule *pMod;
253134254511
253135254512
pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
253136254513
if( pMod ){
253137
- *pTokenizer = pMod->x;
253138
- *ppUserData = pMod->pUserData;
253139
- }else{
253140
- memset(pTokenizer, 0, sizeof(fts5_tokenizer));
253141
- rc = SQLITE_ERROR;
253142
- }
253143
-
253144
- return rc;
253145
-}
253146
-
253147
-int fts5GetTokenizer(
253148
- Fts5Global *pGlobal,
253149
- const char **azArg,
253150
- int nArg,
253151
- Fts5Config *pConfig,
253152
- char **pzErr
253153
-){
253154
- Fts5TokenizerModule *pMod;
253155
- int rc = SQLITE_OK;
253156
-
253157
- pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
253158
- if( pMod==0 ){
253159
- assert( nArg>0 );
253160
- rc = SQLITE_ERROR;
253161
- if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
253162
- }else{
253163
- rc = pMod->x.xCreate(
253164
- pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
253165
- );
253166
- pConfig->t.pTokApi = &pMod->x;
253167
- if( rc!=SQLITE_OK ){
253168
- if( pzErr && rc!=SQLITE_NOMEM ){
253169
- *pzErr = sqlite3_mprintf("error in tokenizer constructor");
253170
- }
253171
- }else{
253172
- pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
253173
- pMod->x.xCreate, pConfig->t.pTok
253174
- );
253175
- }
253176
- }
253177
-
253178
- if( rc!=SQLITE_OK ){
253179
- pConfig->t.pTokApi = 0;
253180
- pConfig->t.pTok = 0;
254514
+ if( pMod->bV2Native==0 ){
254515
+ *ppUserData = pMod->pUserData;
254516
+ }else{
254517
+ *ppUserData = (void*)pMod;
254518
+ }
254519
+ *pTokenizer = pMod->x1;
254520
+ }else{
254521
+ memset(pTokenizer, 0, sizeof(*pTokenizer));
254522
+ *ppUserData = 0;
254523
+ rc = SQLITE_ERROR;
253181254524
}
253182254525
253183254526
return rc;
253184254527
}
253185254528
253186254529
/*
253187254530
** Attempt to instantiate the tokenizer.
253188254531
*/
253189254532
static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
253190
- return fts5GetTokenizer(
253191
- pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg,
253192
- pConfig, pConfig->pzErrmsg
253193
- );
254533
+ const char **azArg = pConfig->t.azArg;
254534
+ const int nArg = pConfig->t.nArg;
254535
+ Fts5TokenizerModule *pMod = 0;
254536
+ int rc = SQLITE_OK;
254537
+
254538
+ pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]);
254539
+ if( pMod==0 ){
254540
+ assert( nArg>0 );
254541
+ rc = SQLITE_ERROR;
254542
+ sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]);
254543
+ }else{
254544
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0;
254545
+ if( pMod->bV2Native ){
254546
+ xCreate = pMod->x2.xCreate;
254547
+ pConfig->t.pApi2 = &pMod->x2;
254548
+ }else{
254549
+ pConfig->t.pApi1 = &pMod->x1;
254550
+ xCreate = pMod->x1.xCreate;
254551
+ }
254552
+
254553
+ rc = xCreate(pMod->pUserData,
254554
+ (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
254555
+ );
254556
+
254557
+ if( rc!=SQLITE_OK ){
254558
+ if( rc!=SQLITE_NOMEM ){
254559
+ sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor");
254560
+ }
254561
+ }else if( pMod->bV2Native==0 ){
254562
+ pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
254563
+ pMod->x1.xCreate, pConfig->t.pTok
254564
+ );
254565
+ }
254566
+ }
254567
+
254568
+ if( rc!=SQLITE_OK ){
254569
+ pConfig->t.pApi1 = 0;
254570
+ pConfig->t.pApi2 = 0;
254571
+ pConfig->t.pTok = 0;
254572
+ }
254573
+
254574
+ return rc;
253194254575
}
253195254576
253196254577
254578
+/*
254579
+** xDestroy callback passed to sqlite3_create_module(). This is invoked
254580
+** when the db handle is being closed. Free memory associated with
254581
+** tokenizers and aux functions registered with this db handle.
254582
+*/
253197254583
static void fts5ModuleDestroy(void *pCtx){
253198254584
Fts5TokenizerModule *pTok, *pNextTok;
253199254585
Fts5Auxiliary *pAux, *pNextAux;
253200254586
Fts5Global *pGlobal = (Fts5Global*)pCtx;
253201254587
@@ -253212,10 +254598,14 @@
253212254598
}
253213254599
253214254600
sqlite3_free(pGlobal);
253215254601
}
253216254602
254603
+/*
254604
+** Implementation of the fts5() function used by clients to obtain the
254605
+** API pointer.
254606
+*/
253217254607
static void fts5Fts5Func(
253218254608
sqlite3_context *pCtx, /* Function call context */
253219254609
int nArg, /* Number of args */
253220254610
sqlite3_value **apArg /* Function arguments */
253221254611
){
@@ -253235,11 +254625,74 @@
253235254625
int nArg, /* Number of args */
253236254626
sqlite3_value **apUnused /* Function arguments */
253237254627
){
253238254628
assert( nArg==0 );
253239254629
UNUSED_PARAM2(nArg, apUnused);
253240
- sqlite3_result_text(pCtx, "fts5: 2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9", -1, SQLITE_TRANSIENT);
254630
+ sqlite3_result_text(pCtx, "fts5: 2024-09-02 18:41:59 e6bec37ea1ca51e1d048941ce4c5211d8fc5c5e3556a1441f9c79b036843f9e3", -1, SQLITE_TRANSIENT);
254631
+}
254632
+
254633
+/*
254634
+** Implementation of fts5_locale(LOCALE, TEXT) function.
254635
+**
254636
+** If parameter LOCALE is NULL, or a zero-length string, then a copy of
254637
+** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
254638
+** text, and the value returned is a blob consisting of:
254639
+**
254640
+** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
254641
+** * The LOCALE, as utf-8 text, followed by
254642
+** * 0x00, followed by
254643
+** * The TEXT, as utf-8 text.
254644
+**
254645
+** There is no final nul-terminator following the TEXT value.
254646
+*/
254647
+static void fts5LocaleFunc(
254648
+ sqlite3_context *pCtx, /* Function call context */
254649
+ int nArg, /* Number of args */
254650
+ sqlite3_value **apArg /* Function arguments */
254651
+){
254652
+ const char *zLocale = 0;
254653
+ int nLocale = 0;
254654
+ const char *zText = 0;
254655
+ int nText = 0;
254656
+
254657
+ assert( nArg==2 );
254658
+ UNUSED_PARAM(nArg);
254659
+
254660
+ zLocale = (const char*)sqlite3_value_text(apArg[0]);
254661
+ nLocale = sqlite3_value_bytes(apArg[0]);
254662
+
254663
+ zText = (const char*)sqlite3_value_text(apArg[1]);
254664
+ nText = sqlite3_value_bytes(apArg[1]);
254665
+
254666
+ if( zLocale==0 || zLocale[0]=='\0' ){
254667
+ sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
254668
+ }else{
254669
+ u8 *pBlob = 0;
254670
+ u8 *pCsr = 0;
254671
+ int nBlob = 0;
254672
+ const int nHdr = 4;
254673
+ assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 );
254674
+
254675
+ nBlob = nHdr + nLocale + 1 + nText;
254676
+ pBlob = (u8*)sqlite3_malloc(nBlob);
254677
+ if( pBlob==0 ){
254678
+ sqlite3_result_error_nomem(pCtx);
254679
+ return;
254680
+ }
254681
+
254682
+ pCsr = pBlob;
254683
+ memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr);
254684
+ pCsr += nHdr;
254685
+ memcpy(pCsr, zLocale, nLocale);
254686
+ pCsr += nLocale;
254687
+ (*pCsr++) = 0x00;
254688
+ if( zText ) memcpy(pCsr, zText, nText);
254689
+ assert( &pCsr[nText]==&pBlob[nBlob] );
254690
+
254691
+ sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
254692
+ sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE);
254693
+ }
253241254694
}
253242254695
253243254696
/*
253244254697
** Return true if zName is the extension on one of the shadow tables used
253245254698
** by this module.
@@ -253330,14 +254783,16 @@
253330254783
rc = SQLITE_NOMEM;
253331254784
}else{
253332254785
void *p = (void*)pGlobal;
253333254786
memset(pGlobal, 0, sizeof(Fts5Global));
253334254787
pGlobal->db = db;
253335
- pGlobal->api.iVersion = 2;
254788
+ pGlobal->api.iVersion = 3;
253336254789
pGlobal->api.xCreateFunction = fts5CreateAux;
253337254790
pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
253338254791
pGlobal->api.xFindTokenizer = fts5FindTokenizer;
254792
+ pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
254793
+ pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
253339254794
rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
253340254795
if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
253341254796
if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
253342254797
if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
253343254798
if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -253351,10 +254806,17 @@
253351254806
rc = sqlite3_create_function(
253352254807
db, "fts5_source_id", 0,
253353254808
SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
253354254809
p, fts5SourceIdFunc, 0, 0
253355254810
);
254811
+ }
254812
+ if( rc==SQLITE_OK ){
254813
+ rc = sqlite3_create_function(
254814
+ db, "fts5_locale", 2,
254815
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
254816
+ p, fts5LocaleFunc, 0, 0
254817
+ );
253356254818
}
253357254819
}
253358254820
253359254821
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
253360254822
** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -253426,17 +254888,44 @@
253426254888
253427254889
253428254890
253429254891
/* #include "fts5Int.h" */
253430254892
254893
+/*
254894
+** pSavedRow:
254895
+** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
254896
+** does a by-rowid lookup to retrieve a single row from the %_content
254897
+** table or equivalent external-content table/view.
254898
+**
254899
+** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
254900
+** values for a row being UPDATEd. In that case, the SQL statement is
254901
+** not reset and pSavedRow is set to point at it. This is so that the
254902
+** insert operation that follows the delete may access the original
254903
+** row values for any new values for which sqlite3_value_nochange() returns
254904
+** true. i.e. if the user executes:
254905
+**
254906
+** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
254907
+** ...
254908
+** UPDATE fts SET a=?, b=? WHERE rowid=?;
254909
+**
254910
+** then the value passed to the xUpdate() method of this table as the
254911
+** new.c value is an sqlite3_value_nochange() value. So in this case it
254912
+** must be read from the saved row stored in Fts5Storage.pSavedRow.
254913
+**
254914
+** This is necessary - using sqlite3_value_nochange() instead of just having
254915
+** SQLite pass the original value back via xUpdate() - so as not to discard
254916
+** any locale information associated with such values.
254917
+**
254918
+*/
253431254919
struct Fts5Storage {
253432254920
Fts5Config *pConfig;
253433254921
Fts5Index *pIndex;
253434254922
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
253435254923
i64 nTotalRow; /* Total number of rows in FTS table */
253436254924
i64 *aTotalSize; /* Total sizes of each column */
253437
- sqlite3_stmt *aStmt[11];
254925
+ sqlite3_stmt *pSavedRow;
254926
+ sqlite3_stmt *aStmt[12];
253438254927
};
253439254928
253440254929
253441254930
#if FTS5_STMT_SCAN_ASC!=0
253442254931
# error "FTS5_STMT_SCAN_ASC mismatch"
@@ -253446,18 +254935,19 @@
253446254935
#endif
253447254936
#if FTS5_STMT_LOOKUP!=2
253448254937
# error "FTS5_STMT_LOOKUP mismatch"
253449254938
#endif
253450254939
253451
-#define FTS5_STMT_INSERT_CONTENT 3
253452
-#define FTS5_STMT_REPLACE_CONTENT 4
253453
-#define FTS5_STMT_DELETE_CONTENT 5
253454
-#define FTS5_STMT_REPLACE_DOCSIZE 6
253455
-#define FTS5_STMT_DELETE_DOCSIZE 7
253456
-#define FTS5_STMT_LOOKUP_DOCSIZE 8
253457
-#define FTS5_STMT_REPLACE_CONFIG 9
253458
-#define FTS5_STMT_SCAN 10
254940
+#define FTS5_STMT_LOOKUP2 3
254941
+#define FTS5_STMT_INSERT_CONTENT 4
254942
+#define FTS5_STMT_REPLACE_CONTENT 5
254943
+#define FTS5_STMT_DELETE_CONTENT 6
254944
+#define FTS5_STMT_REPLACE_DOCSIZE 7
254945
+#define FTS5_STMT_DELETE_DOCSIZE 8
254946
+#define FTS5_STMT_LOOKUP_DOCSIZE 9
254947
+#define FTS5_STMT_REPLACE_CONFIG 10
254948
+#define FTS5_STMT_SCAN 11
253459254949
253460254950
/*
253461254951
** Prepare the two insert statements - Fts5Storage.pInsertContent and
253462254952
** Fts5Storage.pInsertDocsize - if they have not already been prepared.
253463254953
** Return SQLITE_OK if successful, or an SQLite error code if an error
@@ -253483,10 +254973,11 @@
253483254973
if( p->aStmt[eStmt]==0 ){
253484254974
const char *azStmt[] = {
253485254975
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
253486254976
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
253487254977
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
254978
+ "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
253488254979
253489254980
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
253490254981
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
253491254982
"DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
253492254983
"REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
@@ -253497,10 +254988,12 @@
253497254988
"REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
253498254989
"SELECT %s FROM %s AS T", /* SCAN */
253499254990
};
253500254991
Fts5Config *pC = p->pConfig;
253501254992
char *zSql = 0;
254993
+
254994
+ assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
253502254995
253503254996
switch( eStmt ){
253504254997
case FTS5_STMT_SCAN:
253505254998
zSql = sqlite3_mprintf(azStmt[eStmt],
253506254999
pC->zContentExprlist, pC->zContent
@@ -253514,10 +255007,11 @@
253514255007
pC->zContentRowid
253515255008
);
253516255009
break;
253517255010
253518255011
case FTS5_STMT_LOOKUP:
255012
+ case FTS5_STMT_LOOKUP2:
253519255013
zSql = sqlite3_mprintf(azStmt[eStmt],
253520255014
pC->zContentExprlist, pC->zContent, pC->zContentRowid
253521255015
);
253522255016
break;
253523255017
@@ -253560,11 +255054,11 @@
253560255054
253561255055
if( zSql==0 ){
253562255056
rc = SQLITE_NOMEM;
253563255057
}else{
253564255058
int f = SQLITE_PREPARE_PERSISTENT;
253565
- if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
255059
+ if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
253566255060
p->pConfig->bLock++;
253567255061
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
253568255062
p->pConfig->bLock--;
253569255063
sqlite3_free(zSql);
253570255064
if( rc!=SQLITE_OK && pzErrMsg ){
@@ -253808,74 +255302,141 @@
253808255302
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
253809255303
pCtx->szCol++;
253810255304
}
253811255305
return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
253812255306
}
255307
+
255308
+/*
255309
+** This function is used as part of an UPDATE statement that modifies the
255310
+** rowid of a row. In that case, this function is called first to set
255311
+** Fts5Storage.pSavedRow to point to a statement that may be used to
255312
+** access the original values of the row being deleted - iDel.
255313
+**
255314
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
255315
+** It is not considered an error if row iDel does not exist. In this case
255316
+** pSavedRow is not set and SQLITE_OK returned.
255317
+*/
255318
+static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
255319
+ int rc = SQLITE_OK;
255320
+ sqlite3_stmt *pSeek = 0;
255321
+
255322
+ assert( p->pSavedRow==0 );
255323
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
255324
+ if( rc==SQLITE_OK ){
255325
+ sqlite3_bind_int64(pSeek, 1, iDel);
255326
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
255327
+ rc = sqlite3_reset(pSeek);
255328
+ }else{
255329
+ p->pSavedRow = pSeek;
255330
+ }
255331
+ }
255332
+
255333
+ return rc;
255334
+}
253813255335
253814255336
/*
253815255337
** If a row with rowid iDel is present in the %_content table, add the
253816255338
** delete-markers to the FTS index necessary to delete it. Do not actually
253817255339
** remove the %_content row at this time though.
255340
+**
255341
+** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
255342
+** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
255343
+** the original values of the row being deleted. This is used by UPDATE
255344
+** statements.
253818255345
*/
253819255346
static int fts5StorageDeleteFromIndex(
253820255347
Fts5Storage *p,
253821255348
i64 iDel,
253822
- sqlite3_value **apVal
255349
+ sqlite3_value **apVal,
255350
+ int bSaveRow /* True to set pSavedRow */
253823255351
){
253824255352
Fts5Config *pConfig = p->pConfig;
253825255353
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
253826255354
int rc = SQLITE_OK; /* Return code */
253827255355
int rc2; /* sqlite3_reset() return code */
253828255356
int iCol;
253829255357
Fts5InsertCtx ctx;
253830255358
255359
+ assert( bSaveRow==0 || apVal==0 );
255360
+ assert( bSaveRow==0 || bSaveRow==1 );
255361
+ assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
255362
+
253831255363
if( apVal==0 ){
253832
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
253833
- if( rc!=SQLITE_OK ) return rc;
253834
- sqlite3_bind_int64(pSeek, 1, iDel);
253835
- if( sqlite3_step(pSeek)!=SQLITE_ROW ){
253836
- return sqlite3_reset(pSeek);
255364
+ if( p->pSavedRow && bSaveRow ){
255365
+ pSeek = p->pSavedRow;
255366
+ p->pSavedRow = 0;
255367
+ }else{
255368
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
255369
+ if( rc!=SQLITE_OK ) return rc;
255370
+ sqlite3_bind_int64(pSeek, 1, iDel);
255371
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
255372
+ return sqlite3_reset(pSeek);
255373
+ }
253837255374
}
253838255375
}
253839255376
253840255377
ctx.pStorage = p;
253841255378
ctx.iCol = -1;
253842255379
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
253843255380
if( pConfig->abUnindexed[iCol-1]==0 ){
253844
- const char *zText;
253845
- int nText;
255381
+ sqlite3_value *pVal = 0;
255382
+ const char *pText = 0;
255383
+ int nText = 0;
255384
+ int bReset = 0;
255385
+
253846255386
assert( pSeek==0 || apVal==0 );
253847255387
assert( pSeek!=0 || apVal!=0 );
253848255388
if( pSeek ){
253849
- zText = (const char*)sqlite3_column_text(pSeek, iCol);
253850
- nText = sqlite3_column_bytes(pSeek, iCol);
253851
- }else if( ALWAYS(apVal) ){
253852
- zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
253853
- nText = sqlite3_value_bytes(apVal[iCol-1]);
255389
+ pVal = sqlite3_column_value(pSeek, iCol);
253854255390
}else{
253855
- continue;
255391
+ pVal = apVal[iCol-1];
253856255392
}
253857
- ctx.szCol = 0;
253858
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
253859
- zText, nText, (void*)&ctx, fts5StorageInsertCallback
255393
+
255394
+ rc = sqlite3Fts5ExtractText(
255395
+ pConfig, pVal, pSeek!=0, &bReset, &pText, &nText
253860255396
);
253861
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
253862
- if( p->aTotalSize[iCol-1]<0 && rc==SQLITE_OK ){
253863
- rc = FTS5_CORRUPT;
255397
+ if( rc==SQLITE_OK ){
255398
+ ctx.szCol = 0;
255399
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
255400
+ pText, nText, (void*)&ctx, fts5StorageInsertCallback
255401
+ );
255402
+ p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
255403
+ if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
255404
+ rc = FTS5_CORRUPT;
255405
+ }
255406
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253864255407
}
253865255408
}
253866255409
}
253867255410
if( rc==SQLITE_OK && p->nTotalRow<1 ){
253868255411
rc = FTS5_CORRUPT;
253869255412
}else{
253870255413
p->nTotalRow--;
253871255414
}
253872255415
253873
- rc2 = sqlite3_reset(pSeek);
253874
- if( rc==SQLITE_OK ) rc = rc2;
255416
+ if( rc==SQLITE_OK && bSaveRow ){
255417
+ assert( p->pSavedRow==0 );
255418
+ p->pSavedRow = pSeek;
255419
+ }else{
255420
+ rc2 = sqlite3_reset(pSeek);
255421
+ if( rc==SQLITE_OK ) rc = rc2;
255422
+ }
253875255423
return rc;
253876255424
}
255425
+
255426
+/*
255427
+** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
255428
+** should be called by the xUpdate() method of the fts5 table before
255429
+** returning from any operation that may have set Fts5Storage.pSavedRow.
255430
+*/
255431
+static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
255432
+ assert( pStorage->pSavedRow==0
255433
+ || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
255434
+ );
255435
+ sqlite3_reset(pStorage->pSavedRow);
255436
+ pStorage->pSavedRow = 0;
255437
+}
253877255438
253878255439
/*
253879255440
** This function is called to process a DELETE on a contentless_delete=1
253880255441
** table. It adds the tombstone required to delete the entry with rowid
253881255442
** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
@@ -253929,16 +255490,16 @@
253929255490
if( p->pConfig->bContentlessDelete ){
253930255491
i64 iOrigin = 0;
253931255492
rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
253932255493
sqlite3_bind_int64(pReplace, 3, iOrigin);
253933255494
}
253934
- if( rc==SQLITE_OK ){
253935
- sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
253936
- sqlite3_step(pReplace);
253937
- rc = sqlite3_reset(pReplace);
253938
- sqlite3_bind_null(pReplace, 2);
253939
- }
255495
+ }
255496
+ if( rc==SQLITE_OK ){
255497
+ sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
255498
+ sqlite3_step(pReplace);
255499
+ rc = sqlite3_reset(pReplace);
255500
+ sqlite3_bind_null(pReplace, 2);
253940255501
}
253941255502
}
253942255503
return rc;
253943255504
}
253944255505
@@ -253988,11 +255549,16 @@
253988255549
}
253989255550
253990255551
/*
253991255552
** Remove a row from the FTS table.
253992255553
*/
253993
-static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
255554
+static int sqlite3Fts5StorageDelete(
255555
+ Fts5Storage *p, /* Storage object */
255556
+ i64 iDel, /* Rowid to delete from table */
255557
+ sqlite3_value **apVal, /* Optional - values to remove from index */
255558
+ int bSaveRow /* If true, set pSavedRow for deleted row */
255559
+){
253994255560
Fts5Config *pConfig = p->pConfig;
253995255561
int rc;
253996255562
sqlite3_stmt *pDel = 0;
253997255563
253998255564
assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
@@ -254005,11 +255571,11 @@
254005255571
254006255572
if( rc==SQLITE_OK ){
254007255573
if( p->pConfig->bContentlessDelete ){
254008255574
rc = fts5StorageContentlessDelete(p, iDel);
254009255575
}else{
254010
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
255576
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
254011255577
}
254012255578
}
254013255579
254014255580
/* Delete the %_docsize record */
254015255581
if( rc==SQLITE_OK && pConfig->bColumnsize ){
@@ -254094,18 +255660,25 @@
254094255660
sqlite3Fts5BufferZero(&buf);
254095255661
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
254096255662
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
254097255663
ctx.szCol = 0;
254098255664
if( pConfig->abUnindexed[ctx.iCol]==0 ){
254099
- const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
254100
- int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
254101
- rc = sqlite3Fts5Tokenize(pConfig,
254102
- FTS5_TOKENIZE_DOCUMENT,
254103
- zText, nText,
254104
- (void*)&ctx,
254105
- fts5StorageInsertCallback
254106
- );
255665
+ int bReset = 0; /* True if tokenizer locale must be reset */
255666
+ int nText = 0; /* Size of pText in bytes */
255667
+ const char *pText = 0; /* Pointer to buffer containing text value */
255668
+ sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
255669
+
255670
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText);
255671
+ if( rc==SQLITE_OK ){
255672
+ rc = sqlite3Fts5Tokenize(pConfig,
255673
+ FTS5_TOKENIZE_DOCUMENT,
255674
+ pText, nText,
255675
+ (void*)&ctx,
255676
+ fts5StorageInsertCallback
255677
+ );
255678
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255679
+ }
254107255680
}
254108255681
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
254109255682
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
254110255683
}
254111255684
p->nTotalRow++;
@@ -254185,11 +255758,35 @@
254185255758
}else{
254186255759
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
254187255760
int i; /* Counter variable */
254188255761
rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
254189255762
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
254190
- rc = sqlite3_bind_value(pInsert, i, apVal[i]);
255763
+ sqlite3_value *pVal = apVal[i];
255764
+ if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
255765
+ /* This is an UPDATE statement, and column (i-2) was not modified.
255766
+ ** Retrieve the value from Fts5Storage.pSavedRow instead. */
255767
+ pVal = sqlite3_column_value(p->pSavedRow, i-1);
255768
+ }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
255769
+ assert( pConfig->bLocale );
255770
+ assert( i>1 );
255771
+ if( pConfig->abUnindexed[i-2] ){
255772
+ /* At attempt to insert an fts5_locale() value into an UNINDEXED
255773
+ ** column. Strip the locale away and just bind the text. */
255774
+ const char *pText = 0;
255775
+ int nText = 0;
255776
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
255777
+ sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
255778
+ }else{
255779
+ const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
255780
+ int nBlob = sqlite3_value_bytes(pVal);
255781
+ assert( nBlob>4 );
255782
+ sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
255783
+ }
255784
+ continue;
255785
+ }
255786
+
255787
+ rc = sqlite3_bind_value(pInsert, i, pVal);
254191255788
}
254192255789
if( rc==SQLITE_OK ){
254193255790
sqlite3_step(pInsert);
254194255791
rc = sqlite3_reset(pInsert);
254195255792
}
@@ -254220,18 +255817,28 @@
254220255817
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
254221255818
}
254222255819
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
254223255820
ctx.szCol = 0;
254224255821
if( pConfig->abUnindexed[ctx.iCol]==0 ){
254225
- const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
254226
- int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
254227
- rc = sqlite3Fts5Tokenize(pConfig,
254228
- FTS5_TOKENIZE_DOCUMENT,
254229
- zText, nText,
254230
- (void*)&ctx,
254231
- fts5StorageInsertCallback
254232
- );
255822
+ int bReset = 0; /* True if tokenizer locale must be reset */
255823
+ int nText = 0; /* Size of pText in bytes */
255824
+ const char *pText = 0; /* Pointer to buffer containing text value */
255825
+ sqlite3_value *pVal = apVal[ctx.iCol+2];
255826
+ int bDisk = 0;
255827
+ if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
255828
+ pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
255829
+ bDisk = 1;
255830
+ }
255831
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText);
255832
+ if( rc==SQLITE_OK ){
255833
+ assert( bReset==0 || pConfig->bLocale );
255834
+ rc = sqlite3Fts5Tokenize(pConfig,
255835
+ FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
255836
+ fts5StorageInsertCallback
255837
+ );
255838
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255839
+ }
254233255840
}
254234255841
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
254235255842
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
254236255843
}
254237255844
p->nTotalRow++;
@@ -254398,18 +256005,26 @@
254398256005
ctx.szCol = 0;
254399256006
if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
254400256007
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
254401256008
}
254402256009
if( rc==SQLITE_OK ){
254403
- const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
254404
- int nText = sqlite3_column_bytes(pScan, i+1);
254405
- rc = sqlite3Fts5Tokenize(pConfig,
254406
- FTS5_TOKENIZE_DOCUMENT,
254407
- zText, nText,
254408
- (void*)&ctx,
254409
- fts5StorageIntegrityCallback
256010
+ int bReset = 0; /* True if tokenizer locale must be reset */
256011
+ int nText = 0; /* Size of pText in bytes */
256012
+ const char *pText = 0; /* Pointer to buffer containing text value */
256013
+
256014
+ rc = sqlite3Fts5ExtractText(pConfig,
256015
+ sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText
254410256016
);
256017
+ if( rc==SQLITE_OK ){
256018
+ rc = sqlite3Fts5Tokenize(pConfig,
256019
+ FTS5_TOKENIZE_DOCUMENT,
256020
+ pText, nText,
256021
+ (void*)&ctx,
256022
+ fts5StorageIntegrityCallback
256023
+ );
256024
+ if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256025
+ }
254411256026
}
254412256027
if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
254413256028
rc = FTS5_CORRUPT;
254414256029
}
254415256030
aTotalSize[i] += ctx.szCol;
@@ -254720,11 +256335,11 @@
254720256335
rc = SQLITE_NOMEM;
254721256336
}else{
254722256337
int i;
254723256338
memset(p, 0, sizeof(AsciiTokenizer));
254724256339
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
254725
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
256340
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
254726256341
const char *zArg = azArg[i+1];
254727256342
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
254728256343
fts5AsciiAddExceptions(p, zArg, 1);
254729256344
}else
254730256345
if( 0==sqlite3_stricmp(azArg[i], "separators") ){
@@ -254731,11 +256346,10 @@
254731256346
fts5AsciiAddExceptions(p, zArg, 0);
254732256347
}else{
254733256348
rc = SQLITE_ERROR;
254734256349
}
254735256350
}
254736
- if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
254737256351
if( rc!=SQLITE_OK ){
254738256352
fts5AsciiDelete((Fts5Tokenizer*)p);
254739256353
p = 0;
254740256354
}
254741256355
}
@@ -255023,20 +256637,20 @@
255023256637
if( p->aFold==0 ){
255024256638
rc = SQLITE_NOMEM;
255025256639
}
255026256640
255027256641
/* Search for a "categories" argument */
255028
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
256642
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
255029256643
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
255030256644
zCat = azArg[i+1];
255031256645
}
255032256646
}
255033256647
if( rc==SQLITE_OK ){
255034256648
rc = unicodeSetCategories(p, zCat);
255035256649
}
255036256650
255037
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
256651
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
255038256652
const char *zArg = azArg[i+1];
255039256653
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
255040256654
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
255041256655
rc = SQLITE_ERROR;
255042256656
}else{
@@ -255057,12 +256671,10 @@
255057256671
/* no-op */
255058256672
}else{
255059256673
rc = SQLITE_ERROR;
255060256674
}
255061256675
}
255062
- if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
255063
-
255064256676
}else{
255065256677
rc = SQLITE_NOMEM;
255066256678
}
255067256679
if( rc!=SQLITE_OK ){
255068256680
fts5UnicodeDelete((Fts5Tokenizer*)p);
@@ -255197,11 +256809,11 @@
255197256809
** stemming. */
255198256810
#define FTS5_PORTER_MAX_TOKEN 64
255199256811
255200256812
typedef struct PorterTokenizer PorterTokenizer;
255201256813
struct PorterTokenizer {
255202
- fts5_tokenizer tokenizer; /* Parent tokenizer module */
256814
+ fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
255203256815
Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
255204256816
char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
255205256817
};
255206256818
255207256819
/*
@@ -255209,11 +256821,11 @@
255209256821
*/
255210256822
static void fts5PorterDelete(Fts5Tokenizer *pTok){
255211256823
if( pTok ){
255212256824
PorterTokenizer *p = (PorterTokenizer*)pTok;
255213256825
if( p->pTokenizer ){
255214
- p->tokenizer.xDelete(p->pTokenizer);
256826
+ p->tokenizer_v2.xDelete(p->pTokenizer);
255215256827
}
255216256828
sqlite3_free(p);
255217256829
}
255218256830
}
255219256831
@@ -255228,26 +256840,28 @@
255228256840
fts5_api *pApi = (fts5_api*)pCtx;
255229256841
int rc = SQLITE_OK;
255230256842
PorterTokenizer *pRet;
255231256843
void *pUserdata = 0;
255232256844
const char *zBase = "unicode61";
256845
+ fts5_tokenizer_v2 *pV2 = 0;
255233256846
255234256847
if( nArg>0 ){
255235256848
zBase = azArg[0];
255236256849
}
255237256850
255238256851
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
255239256852
if( pRet ){
255240256853
memset(pRet, 0, sizeof(PorterTokenizer));
255241
- rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
256854
+ rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
255242256855
}else{
255243256856
rc = SQLITE_NOMEM;
255244256857
}
255245256858
if( rc==SQLITE_OK ){
255246256859
int nArg2 = (nArg>0 ? nArg-1 : 0);
255247
- const char **azArg2 = (nArg2 ? &azArg[1] : 0);
255248
- rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
256860
+ const char **az2 = (nArg2 ? &azArg[1] : 0);
256861
+ memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
256862
+ rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
255249256863
}
255250256864
255251256865
if( rc!=SQLITE_OK ){
255252256866
fts5PorterDelete((Fts5Tokenizer*)pRet);
255253256867
pRet = 0;
@@ -255894,19 +257508,20 @@
255894257508
static int fts5PorterTokenize(
255895257509
Fts5Tokenizer *pTokenizer,
255896257510
void *pCtx,
255897257511
int flags,
255898257512
const char *pText, int nText,
257513
+ const char *pLoc, int nLoc,
255899257514
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
255900257515
){
255901257516
PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
255902257517
PorterContext sCtx;
255903257518
sCtx.xToken = xToken;
255904257519
sCtx.pCtx = pCtx;
255905257520
sCtx.aBuf = p->aBuf;
255906
- return p->tokenizer.xTokenize(
255907
- p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
257521
+ return p->tokenizer_v2.xTokenize(
257522
+ p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
255908257523
);
255909257524
}
255910257525
255911257526
/**************************************************************************
255912257527
** Start of trigram implementation.
@@ -255932,45 +257547,50 @@
255932257547
const char **azArg,
255933257548
int nArg,
255934257549
Fts5Tokenizer **ppOut
255935257550
){
255936257551
int rc = SQLITE_OK;
255937
- TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
257552
+ TrigramTokenizer *pNew = 0;
255938257553
UNUSED_PARAM(pUnused);
255939
- if( pNew==0 ){
255940
- rc = SQLITE_NOMEM;
257554
+ if( nArg%2 ){
257555
+ rc = SQLITE_ERROR;
255941257556
}else{
255942257557
int i;
255943
- pNew->bFold = 1;
255944
- pNew->iFoldParam = 0;
255945
- for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
255946
- const char *zArg = azArg[i+1];
255947
- if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
255948
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
255949
- rc = SQLITE_ERROR;
255950
- }else{
255951
- pNew->bFold = (zArg[0]=='0');
255952
- }
255953
- }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
255954
- if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
255955
- rc = SQLITE_ERROR;
255956
- }else{
255957
- pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
255958
- }
255959
- }else{
255960
- rc = SQLITE_ERROR;
255961
- }
255962
- }
255963
- if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
255964
-
255965
- if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
255966
- rc = SQLITE_ERROR;
255967
- }
255968
-
255969
- if( rc!=SQLITE_OK ){
255970
- fts5TriDelete((Fts5Tokenizer*)pNew);
255971
- pNew = 0;
257558
+ pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
257559
+ if( pNew==0 ){
257560
+ rc = SQLITE_NOMEM;
257561
+ }else{
257562
+ pNew->bFold = 1;
257563
+ pNew->iFoldParam = 0;
257564
+
257565
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
257566
+ const char *zArg = azArg[i+1];
257567
+ if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
257568
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
257569
+ rc = SQLITE_ERROR;
257570
+ }else{
257571
+ pNew->bFold = (zArg[0]=='0');
257572
+ }
257573
+ }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
257574
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
257575
+ rc = SQLITE_ERROR;
257576
+ }else{
257577
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
257578
+ }
257579
+ }else{
257580
+ rc = SQLITE_ERROR;
257581
+ }
257582
+ }
257583
+
257584
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
257585
+ rc = SQLITE_ERROR;
257586
+ }
257587
+
257588
+ if( rc!=SQLITE_OK ){
257589
+ fts5TriDelete((Fts5Tokenizer*)pNew);
257590
+ pNew = 0;
257591
+ }
255972257592
}
255973257593
}
255974257594
*ppOut = (Fts5Tokenizer*)pNew;
255975257595
return rc;
255976257596
}
@@ -256091,11 +257711,10 @@
256091257711
const char *zName;
256092257712
fts5_tokenizer x;
256093257713
} aBuiltin[] = {
256094257714
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
256095257715
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
256096
- { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
256097257716
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
256098257717
};
256099257718
256100257719
int rc = SQLITE_OK; /* Return code */
256101257720
int i; /* To iterate through builtin functions */
@@ -256106,11 +257725,24 @@
256106257725
(void*)pApi,
256107257726
&aBuiltin[i].x,
256108257727
0
256109257728
);
256110257729
}
256111
-
257730
+ if( rc==SQLITE_OK ){
257731
+ fts5_tokenizer_v2 sPorter = {
257732
+ 2,
257733
+ fts5PorterCreate,
257734
+ fts5PorterDelete,
257735
+ fts5PorterTokenize
257736
+ };
257737
+ rc = pApi->xCreateTokenizer_v2(pApi,
257738
+ "porter",
257739
+ (void*)pApi,
257740
+ &sPorter,
257741
+ 0
257742
+ );
257743
+ }
256112257744
return rc;
256113257745
}
256114257746
256115257747
/*
256116257748
** 2012-05-25
@@ -256476,10 +258108,13 @@
256476258108
aArray[29] = 1;
256477258109
break;
256478258110
default: return 1; }
256479258111
break;
256480258112
258113
+
258114
+ default:
258115
+ return 1;
256481258116
}
256482258117
return 0;
256483258118
}
256484258119
256485258120
static u16 aFts5UnicodeBlock[] = {
256486258121
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -16,11 +16,11 @@
16 ** if you want a wrapper to interface SQLite with your choice of programming
17 ** language. The code for the "sqlite3" command-line shell is also in a
18 ** separate file. This file contains only code for the core SQLite library.
19 **
20 ** The content in this amalgamation comes from Fossil check-in
21 ** 7a0cdc7edb704a88a77b748cd28f6e00c498.
22 */
23 #define SQLITE_CORE 1
24 #define SQLITE_AMALGAMATION 1
25 #ifndef SQLITE_PRIVATE
26 # define SQLITE_PRIVATE static
@@ -462,11 +462,11 @@
462 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
463 ** [sqlite_version()] and [sqlite_source_id()].
464 */
465 #define SQLITE_VERSION "3.47.0"
466 #define SQLITE_VERSION_NUMBER 3047000
467 #define SQLITE_SOURCE_ID "2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9"
468
469 /*
470 ** CAPI3REF: Run-Time Library Version Numbers
471 ** KEYWORDS: sqlite3_version sqlite3_sourceid
472 **
@@ -5929,18 +5929,28 @@
5929 ** might become a no-op if the function is used as term in an
5930 ** [expression index]. On the other hand, SQL functions that never invoke
5931 ** [sqlite3_result_subtype()] should avoid setting this property, as the
5932 ** purpose of this property is to disable certain optimizations that are
5933 ** incompatible with subtypes.
 
 
 
 
 
 
 
 
 
5934 ** </dd>
5935 ** </dl>
5936 */
5937 #define SQLITE_DETERMINISTIC 0x000000800
5938 #define SQLITE_DIRECTONLY 0x000080000
5939 #define SQLITE_SUBTYPE 0x000100000
5940 #define SQLITE_INNOCUOUS 0x000200000
5941 #define SQLITE_RESULT_SUBTYPE 0x001000000
 
5942
5943 /*
5944 ** CAPI3REF: Deprecated Functions
5945 ** DEPRECATED
5946 **
@@ -7741,13 +7751,15 @@
7741 **
7742 ** ^The estimatedRows value is an estimate of the number of rows that
7743 ** will be returned by the strategy.
7744 **
7745 ** The xBestIndex method may optionally populate the idxFlags field with a
7746 ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
7747 ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
7748 ** assumes that the strategy may visit at most one row.
 
 
7749 **
7750 ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
7751 ** SQLite also assumes that if a call to the xUpdate() method is made as
7752 ** part of the same statement to delete or update a virtual table row and the
7753 ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7807,11 +7819,13 @@
7807 **
7808 ** Virtual table implementations are allowed to set the
7809 ** [sqlite3_index_info].idxFlags field to some combination of
7810 ** these bits.
7811 */
7812 #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
 
 
7813
7814 /*
7815 ** CAPI3REF: Virtual Table Constraint Operator Codes
7816 **
7817 ** These macros define the allowed values for the
@@ -8644,10 +8658,11 @@
8644 #define SQLITE_TESTCTRL_ALWAYS 13
8645 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
8646 #define SQLITE_TESTCTRL_JSON_SELFCHECK 14
8647 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15
8648 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
 
8649 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
8650 #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
8651 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
8652 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
8653 #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13418,13 +13433,36 @@
13418 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13419 ** includes any embedded 0x00 and trailing data.
13420 **
13421 ** This API can be quite slow if used with an FTS5 table created with the
13422 ** "detail=none" or "detail=column" option.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13423 */
13424 struct Fts5ExtensionApi {
13425 int iVersion; /* Currently always set to 3 */
13426
13427 void *(*xUserData)(Fts5Context*);
13428
13429 int (*xColumnCount)(Fts5Context*);
13430 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13462,10 +13500,19 @@
13462 int (*xQueryToken)(Fts5Context*,
13463 int iPhrase, int iToken,
13464 const char **ppToken, int *pnToken
13465 );
13466 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
 
 
 
 
 
 
 
 
 
13467 };
13468
13469 /*
13470 ** CUSTOM AUXILIARY FUNCTIONS
13471 *************************************************************************/
@@ -13474,19 +13521,20 @@
13474 ** CUSTOM TOKENIZERS
13475 **
13476 ** Applications may also register custom tokenizer types. A tokenizer
13477 ** is registered by providing fts5 with a populated instance of the
13478 ** following structure. All structure methods must be defined, setting
 
13479 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13480 ** behaviour. The structure methods are expected to function as follows:
13481 **
13482 ** xCreate:
13483 ** This function is used to allocate and initialize a tokenizer instance.
13484 ** A tokenizer instance is required to actually tokenize text.
13485 **
13486 ** The first argument passed to this function is a copy of the (void*)
13487 ** pointer provided by the application when the fts5_tokenizer object
13488 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
13489 ** The second and third arguments are an array of nul-terminated strings
13490 ** containing the tokenizer arguments, if any, specified following the
13491 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
13492 ** to create the FTS5 table.
@@ -13506,11 +13554,11 @@
13506 ** This function is expected to tokenize the nText byte string indicated
13507 ** by argument pText. pText may or may not be nul-terminated. The first
13508 ** argument passed to this function is a pointer to an Fts5Tokenizer object
13509 ** returned by an earlier call to xCreate().
13510 **
13511 ** The second argument indicates the reason that FTS5 is requesting
13512 ** tokenization of the supplied text. This is always one of the following
13513 ** four values:
13514 **
13515 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
13516 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -13529,10 +13577,17 @@
13529 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
13530 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
13531 ** function. Or an fts5_api.xColumnSize() request made by the same
13532 ** on a columnsize=0 database.
13533 ** </ul>
 
 
 
 
 
 
 
13534 **
13535 ** For each token in the input string, the supplied callback xToken() must
13536 ** be invoked. The first argument to it should be a copy of the pointer
13537 ** passed as the second argument to xTokenize(). The third and fourth
13538 ** arguments are a pointer to a buffer containing the token text, and the
@@ -13552,10 +13607,34 @@
13552 ** immediately return a copy of the xToken() return value. Or, if the
13553 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
13554 ** if an error occurs with the xTokenize() implementation itself, it
13555 ** may abandon the tokenization and return any error code other than
13556 ** SQLITE_OK or SQLITE_DONE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13557 **
13558 ** SYNONYM SUPPORT
13559 **
13560 ** Custom tokenizers may also support synonyms. Consider a case in which a
13561 ** user wishes to query for a phrase such as "first place". Using the
@@ -13661,10 +13740,37 @@
13661 ** provide synonyms when tokenizing document text (method (3)) or query
13662 ** text (method (2)), not both. Doing so will not cause any errors, but is
13663 ** inefficient.
13664 */
13665 typedef struct Fts5Tokenizer Fts5Tokenizer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13666 typedef struct fts5_tokenizer fts5_tokenizer;
13667 struct fts5_tokenizer {
13668 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13669 void (*xDelete)(Fts5Tokenizer*);
13670 int (*xTokenize)(Fts5Tokenizer*,
@@ -13679,10 +13785,11 @@
13679 int iStart, /* Byte offset of token within input text */
13680 int iEnd /* Byte offset of end of token within input text */
13681 )
13682 );
13683 };
 
13684
13685 /* Flags that may be passed as the third argument to xTokenize() */
13686 #define FTS5_TOKENIZE_QUERY 0x0001
13687 #define FTS5_TOKENIZE_PREFIX 0x0002
13688 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13699,11 +13806,11 @@
13699 /*************************************************************************
13700 ** FTS5 EXTENSION REGISTRATION API
13701 */
13702 typedef struct fts5_api fts5_api;
13703 struct fts5_api {
13704 int iVersion; /* Currently always set to 2 */
13705
13706 /* Create a new tokenizer */
13707 int (*xCreateTokenizer)(
13708 fts5_api *pApi,
13709 const char *zName,
@@ -13726,10 +13833,29 @@
13726 const char *zName,
13727 void *pUserData,
13728 fts5_extension_function xFunction,
13729 void (*xDestroy)(void*)
13730 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13731 };
13732
13733 /*
13734 ** END OF REGISTRATION API
13735 *************************************************************************/
@@ -14703,10 +14829,12 @@
14703 ** substitute integer for floating-point
14704 */
14705 #ifdef SQLITE_OMIT_FLOATING_POINT
14706 # define double sqlite_int64
14707 # define float sqlite_int64
 
 
14708 # define LONGDOUBLE_TYPE sqlite_int64
14709 # ifndef SQLITE_BIG_DBL
14710 # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
14711 # endif
14712 # define SQLITE_OMIT_DATETIME_FUNCS 1
@@ -15380,10 +15508,11 @@
15380 typedef struct RowSet RowSet;
15381 typedef struct Savepoint Savepoint;
15382 typedef struct Select Select;
15383 typedef struct SQLiteThread SQLiteThread;
15384 typedef struct SelectDest SelectDest;
 
15385 typedef struct SrcItem SrcItem;
15386 typedef struct SrcList SrcList;
15387 typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
15388 typedef struct Table Table;
15389 typedef struct TableLock TableLock;
@@ -19263,10 +19392,20 @@
19263 */
19264 #define EU4_NONE 0 /* Does not use IdList.a.u4 */
19265 #define EU4_IDX 1 /* Uses IdList.a.u4.idx */
19266 #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
19267
 
 
 
 
 
 
 
 
 
 
19268 /*
19269 ** The SrcItem object represents a single term in the FROM clause of a query.
19270 ** The SrcList object is mostly an array of SrcItems.
19271 **
19272 ** The jointype starts out showing the join type between the current table
@@ -19275,33 +19414,44 @@
19275 ** jointype expresses the join between the table and the previous table.
19276 **
19277 ** In the colUsed field, the high-order bit (bit 63) is set if the table
19278 ** contains more than 63 columns and the 64-th or later column is used.
19279 **
19280 ** Union member validity:
 
 
 
19281 **
19282 ** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
19283 ** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
 
 
19284 ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
19285 **
19286 ** u2.pIBIndex fg.isIndexedBy && !fg.isCte
19287 ** u2.pCteUse fg.isCte && !fg.isIndexedBy
 
 
 
 
 
 
 
 
 
 
 
19288 */
19289 struct SrcItem {
19290 Schema *pSchema; /* Schema to which this item is fixed */
19291 char *zDatabase; /* Name of database holding this table */
19292 char *zName; /* Name of the table */
19293 char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
19294 Table *pTab; /* An SQL table corresponding to zName */
19295 Select *pSelect; /* A SELECT statement used in place of a table name */
19296 int addrFillSub; /* Address of subroutine to manifest a subquery */
19297 int regReturn; /* Register holding return address of addrFillSub */
19298 int regResult; /* Registers holding results of a co-routine */
19299 struct {
19300 u8 jointype; /* Type of join between this table and the previous */
19301 unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
19302 unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
 
19303 unsigned isTabFunc :1; /* True if table-valued-function syntax */
19304 unsigned isCorrelated :1; /* True if sub-query is correlated */
19305 unsigned isMaterialized:1; /* This is a materialized view */
19306 unsigned viaCoroutine :1; /* Implemented as a co-routine */
19307 unsigned isRecursive :1; /* True for recursive reference in WITH */
@@ -19311,16 +19461,14 @@
19311 unsigned isUsing :1; /* u3.pUsing is valid */
19312 unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
19313 unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
19314 unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
19315 unsigned rowidUsed :1; /* The ROWID of this table is referenced */
 
 
19316 } fg;
19317 int iCursor; /* The VDBE cursor number used to access this table */
19318 union {
19319 Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
19320 IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
19321 } u3;
19322 Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
19323 union {
19324 char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
19325 ExprList *pFuncArg; /* Arguments to table-valued-function */
19326 u32 nRow; /* Number of rows in a VALUES clause */
@@ -19327,10 +19475,19 @@
19327 } u1;
19328 union {
19329 Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
19330 CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
19331 } u2;
 
 
 
 
 
 
 
 
 
19332 };
19333
19334 /*
19335 ** The OnOrUsing object represents either an ON clause or a USING clause.
19336 ** It can never be both at the same time, but it can be neither.
@@ -19586,12 +19743,14 @@
19586 #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
19587 #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
19588 #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
19589 #define SF_Correlated 0x20000000 /* True if references the outer context */
19590
19591 /* True if S exists and has SF_NestedFrom */
19592 #define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
 
 
19593
19594 /*
19595 ** The results of a SELECT can be distributed in several ways, as defined
19596 ** by one of the following macros. The "SRT" prefix means "SELECT Result
19597 ** Type".
@@ -20979,10 +21138,13 @@
20979 SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
20980 SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
20981 SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
20982 SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
20983 SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
 
 
 
20984 SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
20985 Token*, Select*, OnOrUsing*);
20986 SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
20987 SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
20988 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *);
@@ -22204,10 +22366,13 @@
22204 #ifdef SQLITE_ENABLE_NULL_TRIM
22205 "ENABLE_NULL_TRIM",
22206 #endif
22207 #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
22208 "ENABLE_OFFSET_SQL_FUNC",
 
 
 
22209 #endif
22210 #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
22211 "ENABLE_OVERSIZE_CELL_CHECK",
22212 #endif
22213 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -24521,12 +24686,12 @@
24521 }
24522 if( M<=2 ){
24523 Y--;
24524 M += 12;
24525 }
24526 A = Y/100;
24527 B = 2 - A + (A/4);
24528 X1 = 36525*(Y+4716)/100;
24529 X2 = 306001*(M+1)/10000;
24530 p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
24531 p->validJD = 1;
24532 if( p->validHMS ){
@@ -24706,11 +24871,11 @@
24706
24707 /*
24708 ** Compute the Year, Month, and Day from the julian day number.
24709 */
24710 static void computeYMD(DateTime *p){
24711 int Z, A, B, C, D, E, X1;
24712 if( p->validYMD ) return;
24713 if( !p->validJD ){
24714 p->Y = 2000;
24715 p->M = 1;
24716 p->D = 1;
@@ -24717,12 +24882,12 @@
24717 }else if( !validJulianDay(p->iJD) ){
24718 datetimeError(p);
24719 return;
24720 }else{
24721 Z = (int)((p->iJD + 43200000)/86400000);
24722 A = (int)((Z - 1867216.25)/36524.25);
24723 A = Z + 1 + A - (A/4);
24724 B = A + 1524;
24725 C = (int)((B - 122.1)/365.25);
24726 D = (36525*(C&32767))/100;
24727 E = (int)((B-D)/30.6001);
24728 X1 = (int)(30.6001*E);
@@ -32017,20 +32182,23 @@
32017 pItem = va_arg(ap, SrcItem*);
32018 assert( bArgList==0 );
32019 if( pItem->zAlias && !flag_altform2 ){
32020 sqlite3_str_appendall(pAccum, pItem->zAlias);
32021 }else if( pItem->zName ){
32022 if( pItem->zDatabase ){
32023 sqlite3_str_appendall(pAccum, pItem->zDatabase);
 
 
 
32024 sqlite3_str_append(pAccum, ".", 1);
32025 }
32026 sqlite3_str_appendall(pAccum, pItem->zName);
32027 }else if( pItem->zAlias ){
32028 sqlite3_str_appendall(pAccum, pItem->zAlias);
32029 }else{
32030 Select *pSel = pItem->pSelect;
32031 assert( pSel!=0 ); /* Because of tag-20240424-1 */
32032 if( pSel->selFlags & SF_NestedFrom ){
32033 sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
32034 }else if( pSel->selFlags & SF_MultiValue ){
32035 assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
32036 sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
@@ -32808,13 +32976,13 @@
32808 int n = 0;
32809 char zLine[1000];
32810 sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
32811 x.printfFlags |= SQLITE_PRINTF_INTERNAL;
32812 sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
32813 if( pItem->pTab ){
32814 sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
32815 pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab,
32816 pItem->colUsed,
32817 pItem->fg.rowidUsed ? "+rowid" : "");
32818 }
32819 if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
32820 sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
@@ -32841,27 +33009,34 @@
32841 if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
32842 if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
32843 if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
32844 if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
32845 if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
 
 
 
32846
32847 sqlite3StrAccumFinish(&x);
32848 sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
32849 n = 0;
32850 if( pItem->pSelect ) n++;
32851 if( pItem->fg.isTabFunc ) n++;
32852 if( pItem->fg.isUsing ) n++;
32853 if( pItem->fg.isUsing ){
32854 sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
32855 }
32856 if( pItem->pSelect ){
32857 if( pItem->pTab ){
32858 Table *pTab = pItem->pTab;
 
32859 sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
32860 }
32861 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
32862 sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
 
 
 
32863 }
32864 if( pItem->fg.isTabFunc ){
32865 sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
32866 }
32867 sqlite3TreeViewPop(&pView);
@@ -38721,11 +38896,11 @@
38721 ** Allowed values for the unixFile.ctrlFlags bitmask:
38722 */
38723 #define UNIXFILE_EXCL 0x01 /* Connections from one process only */
38724 #define UNIXFILE_RDONLY 0x02 /* Connection is read only */
38725 #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
38726 #ifndef SQLITE_DISABLE_DIRSYNC
38727 # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
38728 #else
38729 # define UNIXFILE_DIRSYNC 0x00
38730 #endif
38731 #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@@ -76573,11 +76748,11 @@
76573 }
76574 if( pCur->iPage>0
76575 && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
76576 && pIdxKey->errCode==SQLITE_OK
76577 ){
76578 pCur->curFlags &= ~BTCF_ValidOvfl;
76579 if( !pCur->pPage->isInit ){
76580 return SQLITE_CORRUPT_BKPT;
76581 }
76582 goto bypass_moveto_root; /* Start search on the current page */
76583 }
@@ -95267,11 +95442,11 @@
95267 }
95268 break;
95269 }
95270 #endif
95271
95272 #if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE)
95273 /* Opcode: Cast P1 P2 * * *
95274 ** Synopsis: affinity(r[P1])
95275 **
95276 ** Force the value in register P1 to be the type defined by P2.
95277 **
@@ -102547,10 +102722,15 @@
102547 }
102548 if( pTab && !HasRowid(pTab) ){
102549 pTab = 0;
102550 sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
102551 }
 
 
 
 
 
102552 #ifndef SQLITE_OMIT_VIEW
102553 if( pTab && IsView(pTab) ){
102554 pTab = 0;
102555 sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
102556 }
@@ -106731,11 +106911,13 @@
106731 SrcItem *pItem;
106732
106733 pSrc = p->pSrc;
106734 if( ALWAYS(pSrc) ){
106735 for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
106736 if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
 
 
106737 return WRC_Abort;
106738 }
106739 if( pItem->fg.isTabFunc
106740 && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
106741 ){
@@ -107037,11 +107219,11 @@
107037 ){
107038 Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
107039 if( pNew ){
107040 pNew->iTable = pMatch->iCursor;
107041 pNew->iColumn = iColumn;
107042 pNew->y.pTab = pMatch->pTab;
107043 assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
107044 ExprSetProperty(pNew, EP_CanBeNull);
107045 *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
107046 }
107047 }
@@ -107168,24 +107350,28 @@
107168 SrcList *pSrcList = pNC->pSrcList;
107169
107170 if( pSrcList ){
107171 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
107172 u8 hCol;
107173 pTab = pItem->pTab;
107174 assert( pTab!=0 && pTab->zName!=0 );
107175 assert( pTab->nCol>0 || pParse->nErr );
107176 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
107177 if( pItem->fg.isNestedFrom ){
107178 /* In this case, pItem is a subquery that has been formed from a
107179 ** parenthesized subset of the FROM clause terms. Example:
107180 ** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
107181 ** \_________________________/
107182 ** This pItem -------------^
107183 */
107184 int hit = 0;
107185 assert( pItem->pSelect!=0 );
107186 pEList = pItem->pSelect->pEList;
 
 
 
 
107187 assert( pEList!=0 );
107188 assert( pEList->nExpr==pTab->nCol );
107189 for(j=0; j<pEList->nExpr; j++){
107190 int bRowid = 0; /* True if possible rowid match */
107191 if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
@@ -107305,12 +107491,12 @@
107305 ** words non-VIEW candidate terms take precedence over VIEWs.
107306 */
107307 if( cntTab==0
107308 || (cntTab==1
107309 && ALWAYS(pMatch!=0)
107310 && ALWAYS(pMatch->pTab!=0)
107311 && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
107312 && (pTab->tabFlags & TF_Ephemeral)==0)
107313 ){
107314 cntTab = 1;
107315 pMatch = pItem;
107316 }else{
@@ -107327,11 +107513,11 @@
107327 }
107328 }
107329 if( pMatch ){
107330 pExpr->iTable = pMatch->iCursor;
107331 assert( ExprUseYTab(pExpr) );
107332 pExpr->y.pTab = pMatch->pTab;
107333 if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
107334 ExprSetProperty(pExpr, EP_CanBeNull);
107335 }
107336 pSchema = pExpr->y.pTab->pSchema;
107337 }
@@ -107369,11 +107555,11 @@
107369 #endif /* SQLITE_OMIT_TRIGGER */
107370 #ifndef SQLITE_OMIT_UPSERT
107371 if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
107372 Upsert *pUpsert = pNC->uNC.pUpsert;
107373 if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
107374 pTab = pUpsert->pUpsertSrc->a[0].pTab;
107375 pExpr->iTable = EXCLUDED_TABLE_NUMBER;
107376 }
107377 }
107378 #endif /* SQLITE_OMIT_UPSERT */
107379
@@ -107452,15 +107638,15 @@
107452 if( cnt==0
107453 && cntTab>=1
107454 && pMatch
107455 && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
107456 && sqlite3IsRowid(zCol)
107457 && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
107458 ){
107459 cnt = cntTab;
107460 #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
107461 if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){
107462 eNewExprOp = TK_NULL;
107463 }
107464 #endif
107465 if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
107466 pExpr->affExpr = SQLITE_AFF_INTEGER;
@@ -107693,11 +107879,11 @@
107693 Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
107694 if( p ){
107695 SrcItem *pItem = &pSrc->a[iSrc];
107696 Table *pTab;
107697 assert( ExprUseYTab(p) );
107698 pTab = p->y.pTab = pItem->pTab;
107699 p->iTable = pItem->iCursor;
107700 if( p->y.pTab->iPKey==iCol ){
107701 p->iColumn = -1;
107702 }else{
107703 p->iColumn = (ynVar)iCol;
@@ -107812,11 +107998,11 @@
107812 SrcItem *pItem;
107813 assert( pSrcList && pSrcList->nSrc>=1 );
107814 pItem = pSrcList->a;
107815 pExpr->op = TK_COLUMN;
107816 assert( ExprUseYTab(pExpr) );
107817 pExpr->y.pTab = pItem->pTab;
107818 pExpr->iTable = pItem->iCursor;
107819 pExpr->iColumn--;
107820 pExpr->affExpr = SQLITE_AFF_INTEGER;
107821 break;
107822 }
@@ -108118,13 +108304,13 @@
108118 assert( pExpr->pLeft->op==TK_ORDER );
108119 assert( ExprUseXList(pExpr->pLeft) );
108120 sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
108121 }
108122 #ifndef SQLITE_OMIT_WINDOWFUNC
108123 if( pWin ){
108124 Select *pSel = pNC->pWinSelect;
108125 assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) );
108126 if( IN_RENAME_OBJECT==0 ){
108127 sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
108128 if( pParse->db->mallocFailed ) break;
108129 }
108130 sqlite3WalkExprList(pWalker, pWin->pPartition);
@@ -108702,11 +108888,15 @@
108702 ** In this case the ORDER BY clause (p->pOrderBy) should be resolved
108703 ** as if it were part of the sub-query, not the parent. This block
108704 ** moves the pOrderBy down to the sub-query. It will be moved back
108705 ** after the names have been resolved. */
108706 if( p->selFlags & SF_Converted ){
108707 Select *pSub = p->pSrc->a[0].pSelect;
 
 
 
 
108708 assert( p->pSrc->nSrc==1 && p->pOrderBy );
108709 assert( pSub->pPrior && pSub->pOrderBy==0 );
108710 pSub->pOrderBy = p->pOrderBy;
108711 p->pOrderBy = 0;
108712 }
@@ -108714,17 +108904,20 @@
108714 /* Recursively resolve names in all subqueries in the FROM clause
108715 */
108716 if( pOuterNC ) pOuterNC->nNestedSelect++;
108717 for(i=0; i<p->pSrc->nSrc; i++){
108718 SrcItem *pItem = &p->pSrc->a[i];
108719 assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/
108720 if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
 
 
 
108721 int nRef = pOuterNC ? pOuterNC->nRef : 0;
108722 const char *zSavedContext = pParse->zAuthContext;
108723
108724 if( pItem->zName ) pParse->zAuthContext = pItem->zName;
108725 sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
108726 pParse->zAuthContext = zSavedContext;
108727 if( pParse->nErr ) return WRC_Abort;
108728 assert( db->mallocFailed==0 );
108729
108730 /* If the number of references to the outer context changed when
@@ -108822,11 +109015,14 @@
108822 ** the sub-query back to the parent query. At this point each term
108823 ** within the ORDER BY clause has been transformed to an integer value.
108824 ** These integers will be replaced by copies of the corresponding result
108825 ** set expressions by the call to resolveOrderGroupBy() below. */
108826 if( p->selFlags & SF_Converted ){
108827 Select *pSub = p->pSrc->a[0].pSelect;
 
 
 
108828 p->pOrderBy = pSub->pOrderBy;
108829 pSub->pOrderBy = 0;
108830 }
108831
108832 /* Process the ORDER BY clause for singleton SELECT statements.
@@ -109089,11 +109285,11 @@
109089 memset(&sNC, 0, sizeof(sNC));
109090 memset(&sSrc, 0, sizeof(sSrc));
109091 if( pTab ){
109092 sSrc.nSrc = 1;
109093 sSrc.a[0].zName = pTab->zName;
109094 sSrc.a[0].pTab = pTab;
109095 sSrc.a[0].iCursor = -1;
109096 if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
109097 /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
109098 ** schema elements */
109099 type |= NC_FromDDL;
@@ -110986,19 +111182,34 @@
110986 pNew->nSrc = pNew->nAlloc = p->nSrc;
110987 for(i=0; i<p->nSrc; i++){
110988 SrcItem *pNewItem = &pNew->a[i];
110989 const SrcItem *pOldItem = &p->a[i];
110990 Table *pTab;
110991 pNewItem->pSchema = pOldItem->pSchema;
110992 pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110993 pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
110994 pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
110995 pNewItem->fg = pOldItem->fg;
110996 pNewItem->iCursor = pOldItem->iCursor;
110997 pNewItem->addrFillSub = pOldItem->addrFillSub;
110998 pNewItem->regReturn = pOldItem->regReturn;
110999 pNewItem->regResult = pOldItem->regResult;
111000 if( pNewItem->fg.isIndexedBy ){
111001 pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
111002 }else if( pNewItem->fg.isTabFunc ){
111003 pNewItem->u1.pFuncArg =
111004 sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
@@ -111007,15 +111218,14 @@
111007 }
111008 pNewItem->u2 = pOldItem->u2;
111009 if( pNewItem->fg.isCte ){
111010 pNewItem->u2.pCteUse->nUse++;
111011 }
111012 pTab = pNewItem->pTab = pOldItem->pTab;
111013 if( pTab ){
111014 pTab->nTabRef++;
111015 }
111016 pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
111017 if( pOldItem->fg.isUsing ){
111018 assert( pNewItem->fg.isUsing );
111019 pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
111020 }else{
111021 pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
@@ -111085,11 +111295,10 @@
111085 }
111086 *pp = pNew;
111087 pp = &pNew->pPrior;
111088 pNext = pNew;
111089 }
111090
111091 return pRet;
111092 }
111093 #else
111094 SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){
111095 assert( p==0 );
@@ -112105,12 +112314,12 @@
112105 if( p->pLimit ) return 0; /* Has no LIMIT clause */
112106 if( p->pWhere ) return 0; /* Has no WHERE clause */
112107 pSrc = p->pSrc;
112108 assert( pSrc!=0 );
112109 if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
112110 if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
112111 pTab = pSrc->a[0].pTab;
112112 assert( pTab!=0 );
112113 assert( !IsView(pTab) ); /* FROM clause is not a view */
112114 if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
112115 pEList = p->pEList;
112116 assert( pEList!=0 );
@@ -112289,11 +112498,11 @@
112289 int nExpr = pEList->nExpr;
112290
112291 assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
112292 assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
112293 assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
112294 pTab = p->pSrc->a[0].pTab;
112295
112296 /* Code an OP_Transaction and OP_TableLock for <table>. */
112297 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
112298 assert( iDb>=0 && iDb<SQLITE_MAX_DB );
112299 sqlite3CodeVerifySchema(pParse, iDb);
@@ -117727,12 +117936,13 @@
117727 }
117728 if( pStep->pFrom ){
117729 int i;
117730 for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
117731 SrcItem *p = &pStep->pFrom->a[i];
117732 if( p->pSelect ){
117733 sqlite3SelectPrep(pParse, p->pSelect, 0);
 
117734 }
117735 }
117736 }
117737
117738 if( db->mallocFailed ){
@@ -117796,12 +118006,16 @@
117796 sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
117797 sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
117798 }
117799 if( pStep->pFrom ){
117800 int i;
117801 for(i=0; i<pStep->pFrom->nSrc; i++){
117802 sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
 
 
 
 
117803 }
117804 }
117805 }
117806 }
117807
@@ -118044,11 +118258,11 @@
118044 assert( pWalker->pParse->db->mallocFailed );
118045 return WRC_Abort;
118046 }
118047 for(i=0; i<pSrc->nSrc; i++){
118048 SrcItem *pItem = &pSrc->a[i];
118049 if( pItem->pTab==p->pTab ){
118050 renameTokenFind(pWalker->pParse, p, pItem->zName);
118051 }
118052 }
118053 renameWalkWith(pWalker, pSelect);
118054
@@ -121178,24 +121392,25 @@
121178 int iDb = sqlite3FindDbName(db, pFix->zDb);
121179 SrcList *pList = pSelect->pSrc;
121180
121181 if( NEVER(pList==0) ) return WRC_Continue;
121182 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
121183 if( pFix->bTemp==0 ){
121184 if( pItem->zDatabase ){
121185 if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
121186 sqlite3ErrorMsg(pFix->pParse,
121187 "%s %T cannot reference objects in database %s",
121188 pFix->zType, pFix->pName, pItem->zDatabase);
121189 return WRC_Abort;
121190 }
121191 sqlite3DbFree(db, pItem->zDatabase);
121192 pItem->zDatabase = 0;
121193 pItem->fg.notCte = 1;
 
121194 }
121195 pItem->pSchema = pFix->pSchema;
121196 pItem->fg.fromDDL = 1;
 
121197 }
121198 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
121199 if( pList->a[i].fg.isUsing==0
121200 && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
121201 ){
@@ -121484,11 +121699,11 @@
121484 pTab = pParse->pTriggerTab;
121485 }else{
121486 assert( pTabList );
121487 for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
121488 if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
121489 pTab = pTabList->a[iSrc].pTab;
121490 break;
121491 }
121492 }
121493 }
121494 iCol = pExpr->iColumn;
@@ -122087,16 +122302,16 @@
122087 Parse *pParse,
122088 u32 flags,
122089 SrcItem *p
122090 ){
122091 const char *zDb;
122092 assert( p->pSchema==0 || p->zDatabase==0 );
122093 if( p->pSchema ){
122094 int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
122095 zDb = pParse->db->aDb[iDb].zDbSName;
122096 }else{
122097 zDb = p->zDatabase;
 
122098 }
122099 return sqlite3LocateTable(pParse, flags, p->zName, zDb);
122100 }
122101
122102 /*
@@ -125077,19 +125292,21 @@
125077 if( db->mallocFailed ){
125078 goto exit_drop_table;
125079 }
125080 assert( pParse->nErr==0 );
125081 assert( pName->nSrc==1 );
 
 
125082 if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
125083 if( noErr ) db->suppressErr++;
125084 assert( isView==0 || isView==LOCATE_VIEW );
125085 pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
125086 if( noErr ) db->suppressErr--;
125087
125088 if( pTab==0 ){
125089 if( noErr ){
125090 sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
125091 sqlite3ForceNotReadOnly(pParse);
125092 }
125093 goto exit_drop_table;
125094 }
125095 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -126176,19 +126393,21 @@
126176 if( db->mallocFailed ){
126177 goto exit_drop_index;
126178 }
126179 assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
126180 assert( pName->nSrc==1 );
 
 
126181 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
126182 goto exit_drop_index;
126183 }
126184 pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
126185 if( pIndex==0 ){
126186 if( !ifExists ){
126187 sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
126188 }else{
126189 sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
126190 sqlite3ForceNotReadOnly(pParse);
126191 }
126192 pParse->checkSchema = 1;
126193 goto exit_drop_index;
126194 }
@@ -126481,16 +126700,18 @@
126481 }
126482 pItem = &pList->a[pList->nSrc-1];
126483 if( pDatabase && pDatabase->z==0 ){
126484 pDatabase = 0;
126485 }
 
 
126486 if( pDatabase ){
126487 pItem->zName = sqlite3NameFromToken(db, pDatabase);
126488 pItem->zDatabase = sqlite3NameFromToken(db, pTable);
126489 }else{
126490 pItem->zName = sqlite3NameFromToken(db, pTable);
126491 pItem->zDatabase = 0;
126492 }
126493 return pList;
126494 }
126495
126496 /*
@@ -126502,16 +126723,43 @@
126502 assert( pList || pParse->db->mallocFailed );
126503 if( ALWAYS(pList) ){
126504 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
126505 if( pItem->iCursor>=0 ) continue;
126506 pItem->iCursor = pParse->nTab++;
126507 if( pItem->pSelect ){
126508 sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
 
 
 
126509 }
126510 }
126511 }
126512 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126513
126514 /*
126515 ** Delete an entire SrcList including all its substructure.
126516 */
126517 SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
@@ -126518,25 +126766,84 @@
126518 int i;
126519 SrcItem *pItem;
126520 assert( db!=0 );
126521 if( pList==0 ) return;
126522 for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
126523 if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
 
 
 
 
 
 
 
126524 if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
126525 if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
 
 
 
 
 
126526 if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
126527 if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
126528 sqlite3DeleteTable(db, pItem->pTab);
126529 if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
126530 if( pItem->fg.isUsing ){
126531 sqlite3IdListDelete(db, pItem->u3.pUsing);
126532 }else if( pItem->u3.pOn ){
126533 sqlite3ExprDelete(db, pItem->u3.pOn);
126534 }
126535 }
126536 sqlite3DbNNFreeNN(db, pList);
126537 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126538
126539 /*
126540 ** This routine is called by the parser to add a new term to the
126541 ** end of a growing FROM clause. The "p" parameter is the part of
126542 ** the FROM clause that has already been constructed. "p" is NULL
@@ -126583,14 +126890,16 @@
126583 }
126584 assert( pAlias!=0 );
126585 if( pAlias->n ){
126586 pItem->zAlias = sqlite3NameFromToken(db, pAlias);
126587 }
 
126588 if( pSubquery ){
126589 pItem->pSelect = pSubquery;
126590 if( pSubquery->selFlags & SF_NestedFrom ){
126591 pItem->fg.isNestedFrom = 1;
 
126592 }
126593 }
126594 assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
126595 assert( pItem->fg.isUsing==0 );
126596 if( pOnUsing==0 ){
@@ -127864,21 +128173,21 @@
127864 ** return a pointer. Set an error message and return NULL if the table
127865 ** name is not found or if any other error occurs.
127866 **
127867 ** The following fields are initialized appropriate in pSrc:
127868 **
127869 ** pSrc->a[0].pTab Pointer to the Table object
127870 ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
127871 **
127872 */
127873 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
127874 SrcItem *pItem = pSrc->a;
127875 Table *pTab;
127876 assert( pItem && pSrc->nSrc>=1 );
127877 pTab = sqlite3LocateTableItem(pParse, 0, pItem);
127878 if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
127879 pItem->pTab = pTab;
127880 pItem->fg.notCte = 1;
127881 if( pTab ){
127882 pTab->nTabRef++;
127883 if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
127884 pTab = 0;
@@ -127996,11 +128305,12 @@
127996 pWhere = sqlite3ExprDup(db, pWhere, 0);
127997 pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0);
127998 if( pFrom ){
127999 assert( pFrom->nSrc==1 );
128000 pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
128001 pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
 
128002 assert( pFrom->a[0].fg.isUsing==0 );
128003 assert( pFrom->a[0].u3.pOn==0 );
128004 }
128005 pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
128006 SF_IncludeHidden, pLimit);
@@ -128058,11 +128368,11 @@
128058 ** DELETE FROM table_a WHERE rowid IN (
128059 ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
128060 ** );
128061 */
128062
128063 pTab = pSrc->a[0].pTab;
128064 if( HasRowid(pTab) ){
128065 pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
128066 pEList = sqlite3ExprListAppend(
128067 pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
128068 );
@@ -128091,13 +128401,13 @@
128091 }
128092 }
128093
128094 /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
128095 ** and the SELECT subtree. */
128096 pSrc->a[0].pTab = 0;
128097 pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
128098 pSrc->a[0].pTab = pTab;
128099 if( pSrc->a[0].fg.isIndexedBy ){
128100 assert( pSrc->a[0].fg.isCte==0 );
128101 pSrc->a[0].u2.pIBIndex = 0;
128102 pSrc->a[0].fg.isIndexedBy = 0;
128103 sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
@@ -130920,11 +131230,15 @@
130920
130921 /*
130922 ** group_concat(EXPR, ?SEPARATOR?)
130923 ** string_agg(EXPR, SEPARATOR)
130924 **
130925 ** The SEPARATOR goes before the EXPR string. This is tragic. The
 
 
 
 
130926 ** groupConcatInverse() implementation would have been easier if the
130927 ** SEPARATOR were appended after EXPR. And the order is undocumented,
130928 ** so we could change it, in theory. But the old behavior has been
130929 ** around for so long that we dare not, for fear of breaking something.
130930 */
@@ -131024,11 +131338,11 @@
131024 if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
131025 pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
131026 /* pGCC is always non-NULL since groupConcatStep() will have always
131027 ** run first to initialize it */
131028 if( ALWAYS(pGCC) ){
131029 int nVS;
131030 /* Must call sqlite3_value_text() to convert the argument into text prior
131031 ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
131032 (void)sqlite3_value_text(argv[0]);
131033 nVS = sqlite3_value_bytes(argv[0]);
131034 pGCC->nAccum -= 1;
@@ -132675,13 +132989,13 @@
132675 /* Create a SrcList structure containing the child table. We need the
132676 ** child table as a SrcList for sqlite3WhereBegin() */
132677 pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
132678 if( pSrc ){
132679 SrcItem *pItem = pSrc->a;
132680 pItem->pTab = pFKey->pFrom;
132681 pItem->zName = pFKey->pFrom->zName;
132682 pItem->pTab->nTabRef++;
132683 pItem->iCursor = pParse->nTab++;
132684
132685 if( regNew!=0 ){
132686 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
132687 }
@@ -132969,11 +133283,12 @@
132969 }
132970 pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
132971 if( pSrc ){
132972 assert( pSrc->nSrc==1 );
132973 pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
132974 pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
 
132975 }
132976 pSelect = sqlite3SelectNew(pParse,
132977 sqlite3ExprListAppend(pParse, 0, pRaise),
132978 pSrc,
132979 pWhere,
@@ -133703,12 +134018,15 @@
133703 ** co-routine.
133704 */
133705 SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
133706 if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
133707 SrcItem *pItem = &pVal->pSrc->a[0];
133708 sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn);
133709 sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1);
 
 
 
133710 }
133711 }
133712
133713 /*
133714 ** Return true if all expressions in the expression-list passed as the
@@ -133832,56 +134150,67 @@
133832 sqlite3ReadSchema(pParse);
133833 }
133834
133835 if( pRet ){
133836 SelectDest dest;
 
133837 pRet->pSrc->nSrc = 1;
133838 pRet->pPrior = pLeft->pPrior;
133839 pRet->op = pLeft->op;
133840 if( pRet->pPrior ) pRet->selFlags |= SF_Values;
133841 pLeft->pPrior = 0;
133842 pLeft->op = TK_SELECT;
133843 assert( pLeft->pNext==0 );
133844 assert( pRet->pNext==0 );
133845 p = &pRet->pSrc->a[0];
133846 p->pSelect = pLeft;
133847 p->fg.viaCoroutine = 1;
133848 p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
133849 p->regReturn = ++pParse->nMem;
133850 p->iCursor = -1;
 
133851 p->u1.nRow = 2;
133852 sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub);
133853 sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn);
133854
133855 /* Allocate registers for the output of the co-routine. Do so so
133856 ** that there are two unused registers immediately before those
133857 ** used by the co-routine. This allows the code in sqlite3Insert()
133858 ** to use these registers directly, instead of copying the output
133859 ** of the co-routine to a separate array for processing. */
133860 dest.iSdst = pParse->nMem + 3;
133861 dest.nSdst = pLeft->pEList->nExpr;
133862 pParse->nMem += 2 + dest.nSdst;
133863
133864 pLeft->selFlags |= SF_MultiValue;
133865 sqlite3Select(pParse, pLeft, &dest);
133866 p->regResult = dest.iSdst;
133867 assert( pParse->nErr || dest.iSdst>0 );
 
 
 
 
 
 
133868 pLeft = pRet;
133869 }
133870 }else{
133871 p = &pLeft->pSrc->a[0];
133872 assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
133873 p->u1.nRow++;
133874 }
133875
133876 if( pParse->nErr==0 ){
 
133877 assert( p!=0 );
133878 if( p->pSelect->pEList->nExpr!=pRow->nExpr ){
133879 sqlite3SelectWrongNumTermsError(pParse, p->pSelect);
 
 
 
 
 
133880 }else{
133881 sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0);
133882 sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn);
133883 }
133884 }
133885 sqlite3ExprListDelete(pParse->db, pRow);
133886 }
133887
@@ -134228,13 +134557,18 @@
134228 if( pSelect->pSrc->nSrc==1
134229 && pSelect->pSrc->a[0].fg.viaCoroutine
134230 && pSelect->pPrior==0
134231 ){
134232 SrcItem *pItem = &pSelect->pSrc->a[0];
134233 dest.iSDParm = pItem->regReturn;
134234 regFromSelect = pItem->regResult;
134235 nColumn = pItem->pSelect->pEList->nExpr;
 
 
 
 
 
134236 ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
134237 if( bIdListInOrder && nColumn==pTab->nCol ){
134238 regData = regFromSelect;
134239 regRowid = regData - 1;
134240 regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
@@ -136150,11 +136484,11 @@
136150 }
136151 assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
136152 if( pSelect->pSrc->nSrc!=1 ){
136153 return 0; /* FROM clause must have exactly one term */
136154 }
136155 if( pSelect->pSrc->a[0].pSelect ){
136156 return 0; /* FROM clause cannot contain a subquery */
136157 }
136158 if( pSelect->pWhere ){
136159 return 0; /* SELECT may not have a WHERE clause */
136160 }
@@ -143448,15 +143782,17 @@
143448 /*
143449 ** Mark a subquery result column as having been used.
143450 */
143451 SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
143452 assert( pItem!=0 );
143453 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
143454 if( pItem->fg.isNestedFrom ){
143455 ExprList *pResults;
143456 assert( pItem->pSelect!=0 );
143457 pResults = pItem->pSelect->pEList;
 
 
143458 assert( pResults!=0 );
143459 assert( iCol>=0 && iCol<pResults->nExpr );
143460 pResults->a[iCol].fg.bUsed = 1;
143461 }
143462 }
@@ -143486,13 +143822,13 @@
143486 assert( iEnd<pSrc->nSrc );
143487 assert( iStart>=0 );
143488 assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
143489
143490 for(i=iStart; i<=iEnd; i++){
143491 iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
143492 if( iCol>=0
143493 && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
143494 ){
143495 if( piTab ){
143496 sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
143497 *piTab = i;
143498 *piCol = iCol;
@@ -143617,14 +143953,14 @@
143617
143618 pSrc = p->pSrc;
143619 pLeft = &pSrc->a[0];
143620 pRight = &pLeft[1];
143621 for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
143622 Table *pRightTab = pRight->pTab;
143623 u32 joinType;
143624
143625 if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
143626 joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
143627
143628 /* If this is a NATURAL join, synthesize an appropriate USING clause
143629 ** to specify which columns should be joined.
143630 */
@@ -145046,12 +145382,16 @@
145046 int iCol = pExpr->iColumn; /* Index of column in pTab */
145047 while( pNC && !pTab ){
145048 SrcList *pTabList = pNC->pSrcList;
145049 for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
145050 if( j<pTabList->nSrc ){
145051 pTab = pTabList->a[j].pTab;
145052 pS = pTabList->a[j].pSelect;
 
 
 
 
145053 }else{
145054 pNC = pNC->pNext;
145055 }
145056 }
145057
@@ -147099,11 +147439,13 @@
147099 p->pHaving = substExpr(pSubst, p->pHaving);
147100 p->pWhere = substExpr(pSubst, p->pWhere);
147101 pSrc = p->pSrc;
147102 assert( pSrc!=0 );
147103 for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
147104 substSelect(pSubst, pItem->pSelect, 1);
 
 
147105 if( pItem->fg.isTabFunc ){
147106 substExprList(pSubst, pItem->u1.pFuncArg);
147107 }
147108 }
147109 }while( doPrior && (p = p->pPrior)!=0 );
@@ -147130,11 +147472,11 @@
147130 static void recomputeColumnsUsed(
147131 Select *pSelect, /* The complete SELECT statement */
147132 SrcItem *pSrcItem /* Which FROM clause item to recompute */
147133 ){
147134 Walker w;
147135 if( NEVER(pSrcItem->pTab==0) ) return;
147136 memset(&w, 0, sizeof(w));
147137 w.xExprCallback = recomputeColumnsUsedExpr;
147138 w.xSelectCallback = sqlite3SelectWalkNoop;
147139 w.u.pSrcItem = pSrcItem;
147140 pSrcItem->colUsed = 0;
@@ -147170,12 +147512,14 @@
147170 assert( pItem->iCursor < aCsrMap[0] );
147171 if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){
147172 aCsrMap[pItem->iCursor+1] = pParse->nTab++;
147173 }
147174 pItem->iCursor = aCsrMap[pItem->iCursor+1];
147175 for(p=pItem->pSelect; p; p=p->pPrior){
147176 srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
 
 
147177 }
147178 }
147179 }
147180 }
147181
@@ -147482,11 +147826,12 @@
147482 if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
147483 pSrc = p->pSrc;
147484 assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
147485 pSubitem = &pSrc->a[iFrom];
147486 iParent = pSubitem->iCursor;
147487 pSub = pSubitem->pSelect;
 
147488 assert( pSub!=0 );
147489
147490 #ifndef SQLITE_OMIT_WINDOWFUNC
147491 if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */
147492 #endif
@@ -147535,11 +147880,11 @@
147535 **
147536 ** See also tickets #306, #350, and #3300.
147537 */
147538 if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
147539 if( pSubSrc->nSrc>1 /* (3a) */
147540 || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
147541 || (p->selFlags & SF_Distinct)!=0 /* (3d) */
147542 || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
147543 ){
147544 return 0;
147545 }
@@ -147621,18 +147966,22 @@
147621 TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
147622 testcase( i==SQLITE_DENY );
147623 pParse->zAuthContext = zSavedAuthContext;
147624
147625 /* Delete the transient structures associated with the subquery */
147626 pSub1 = pSubitem->pSelect;
147627 sqlite3DbFree(db, pSubitem->zDatabase);
 
 
 
 
 
 
147628 sqlite3DbFree(db, pSubitem->zName);
147629 sqlite3DbFree(db, pSubitem->zAlias);
147630 pSubitem->zDatabase = 0;
147631 pSubitem->zName = 0;
147632 pSubitem->zAlias = 0;
147633 pSubitem->pSelect = 0;
147634 assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
147635
147636 /* If the sub-query is a compound SELECT statement, then (by restrictions
147637 ** 17 and 18 above) it must be a UNION ALL and the parent query must
147638 ** be of the form:
@@ -147669,20 +148018,20 @@
147669 for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
147670 Select *pNew;
147671 ExprList *pOrderBy = p->pOrderBy;
147672 Expr *pLimit = p->pLimit;
147673 Select *pPrior = p->pPrior;
147674 Table *pItemTab = pSubitem->pTab;
147675 pSubitem->pTab = 0;
147676 p->pOrderBy = 0;
147677 p->pPrior = 0;
147678 p->pLimit = 0;
147679 pNew = sqlite3SelectDup(db, p, 0);
147680 p->pLimit = pLimit;
147681 p->pOrderBy = pOrderBy;
147682 p->op = TK_ALL;
147683 pSubitem->pTab = pItemTab;
147684 if( pNew==0 ){
147685 p->pPrior = pPrior;
147686 }else{
147687 pNew->selId = ++pParse->nSelect;
147688 if( aCsrMap && ALWAYS(db->mallocFailed==0) ){
@@ -147693,15 +148042,18 @@
147693 pNew->pNext = p;
147694 p->pPrior = pNew;
147695 TREETRACE(0x4,pParse,p,("compound-subquery flattener"
147696 " creates %u as peer\n",pNew->selId));
147697 }
147698 assert( pSubitem->pSelect==0 );
147699 }
147700 sqlite3DbFree(db, aCsrMap);
147701 if( db->mallocFailed ){
147702 pSubitem->pSelect = pSub1;
 
 
 
147703 return 1;
147704 }
147705
147706 /* Defer deleting the Table object associated with the
147707 ** subquery until code generation is
@@ -147708,20 +148060,20 @@
147708 ** complete, since there may still exist Expr.pTab entries that
147709 ** refer to the subquery even after flattening. Ticket #3346.
147710 **
147711 ** pSubitem->pTab is always non-NULL by test restrictions and tests above.
147712 */
147713 if( ALWAYS(pSubitem->pTab!=0) ){
147714 Table *pTabToDel = pSubitem->pTab;
147715 if( pTabToDel->nTabRef==1 ){
147716 Parse *pToplevel = sqlite3ParseToplevel(pParse);
147717 sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
147718 testcase( pToplevel->earlyCleanup );
147719 }else{
147720 pTabToDel->nTabRef--;
147721 }
147722 pSubitem->pTab = 0;
147723 }
147724
147725 /* The following loop runs once for each term in a compound-subquery
147726 ** flattening (as described above). If we are doing a different kind
147727 ** of flattening - a flattening other than a compound-subquery flattening -
@@ -147773,12 +148125,15 @@
147773 /* Transfer the FROM clause terms from the subquery into the
147774 ** outer query.
147775 */
147776 for(i=0; i<nSubSrc; i++){
147777 SrcItem *pItem = &pSrc->a[i+iFrom];
147778 if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
147779 assert( pItem->fg.isTabFunc==0 );
 
 
 
 
147780 *pItem = pSubSrc->a[i];
147781 pItem->fg.jointype |= ltorj;
147782 iNewParent = pSubSrc->a[i].iCursor;
147783 memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
147784 }
@@ -148458,14 +148813,14 @@
148458
148459 assert( pItem!=0 );
148460 if( pItem->fg.isCorrelated || pItem->fg.isCte ){
148461 return 0;
148462 }
148463 assert( pItem->pTab!=0 );
148464 pTab = pItem->pTab;
148465 assert( pItem->pSelect!=0 );
148466 pSub = pItem->pSelect;
148467 assert( pSub->pEList->nExpr==pTab->nCol );
148468 for(pX=pSub; pX; pX=pX->pPrior){
148469 if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
148470 testcase( pX->selFlags & SF_Distinct );
148471 testcase( pX->selFlags & SF_Aggregate );
@@ -148590,17 +148945,17 @@
148590 assert( !p->pGroupBy );
148591
148592 if( p->pWhere
148593 || p->pEList->nExpr!=1
148594 || p->pSrc->nSrc!=1
148595 || p->pSrc->a[0].pSelect
148596 || pAggInfo->nFunc!=1
148597 || p->pHaving
148598 ){
148599 return 0;
148600 }
148601 pTab = p->pSrc->a[0].pTab;
148602 assert( pTab!=0 );
148603 assert( !IsView(pTab) );
148604 if( !IsOrdinaryTable(pTab) ) return 0;
148605 pExpr = p->pEList->a[0].pExpr;
148606 assert( pExpr!=0 );
@@ -148621,11 +148976,11 @@
148621 ** was such a clause and the named index cannot be found, return
148622 ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
148623 ** pFrom->pIndex and return SQLITE_OK.
148624 */
148625 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
148626 Table *pTab = pFrom->pTab;
148627 char *zIndexedBy = pFrom->u1.zIndexedBy;
148628 Index *pIdx;
148629 assert( pTab!=0 );
148630 assert( pFrom->fg.isIndexedBy!=0 );
148631
@@ -148698,11 +149053,15 @@
148698 db = pParse->db;
148699 pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
148700 if( pNew==0 ) return WRC_Abort;
148701 memset(&dummy, 0, sizeof(dummy));
148702 pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
148703 if( pNewSrc==0 ) return WRC_Abort;
 
 
 
 
148704 *pNew = *p;
148705 p->pSrc = pNewSrc;
148706 p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
148707 p->op = TK_SELECT;
148708 p->pWhere = 0;
@@ -148753,11 +149112,11 @@
148753 SrcItem *pItem, /* FROM clause element to resolve */
148754 With **ppContext /* OUT: WITH clause return value belongs to */
148755 ){
148756 const char *zName = pItem->zName;
148757 With *p;
148758 assert( pItem->zDatabase==0 );
148759 assert( zName!=0 );
148760 for(p=pWith; p; p=p->pOuter){
148761 int i;
148762 for(i=0; i<p->nCte; i++){
148763 if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
@@ -148823,21 +149182,22 @@
148823 SrcItem *pFrom /* The FROM clause term to check */
148824 ){
148825 Cte *pCte; /* Matched CTE (or NULL if no match) */
148826 With *pWith; /* The matching WITH */
148827
148828 assert( pFrom->pTab==0 );
148829 if( pParse->pWith==0 ){
148830 /* There are no WITH clauses in the stack. No match is possible */
148831 return 0;
148832 }
148833 if( pParse->nErr ){
148834 /* Prior errors might have left pParse->pWith in a goofy state, so
148835 ** go no further. */
148836 return 0;
148837 }
148838 if( pFrom->zDatabase!=0 ){
 
148839 /* The FROM term contains a schema qualifier (ex: main.t1) and so
148840 ** it cannot possibly be a CTE reference. */
148841 return 0;
148842 }
148843 if( pFrom->fg.notCte ){
@@ -148869,11 +149229,11 @@
148869 sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
148870 return 2;
148871 }
148872 if( cannotBeFunction(pParse, pFrom) ) return 2;
148873
148874 assert( pFrom->pTab==0 );
148875 pTab = sqlite3DbMallocZero(db, sizeof(Table));
148876 if( pTab==0 ) return 2;
148877 pCteUse = pCte->pUse;
148878 if( pCteUse==0 ){
148879 pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
@@ -148883,42 +149243,47 @@
148883 sqlite3DbFree(db, pTab);
148884 return 2;
148885 }
148886 pCteUse->eM10d = pCte->eM10d;
148887 }
148888 pFrom->pTab = pTab;
148889 pTab->nTabRef = 1;
148890 pTab->zName = sqlite3DbStrDup(db, pCte->zName);
148891 pTab->iPKey = -1;
148892 pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
148893 pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
148894 pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
148895 if( db->mallocFailed ) return 2;
148896 pFrom->pSelect->selFlags |= SF_CopyCte;
148897 assert( pFrom->pSelect );
 
 
148898 if( pFrom->fg.isIndexedBy ){
148899 sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
148900 return 2;
148901 }
 
148902 pFrom->fg.isCte = 1;
148903 pFrom->u2.pCteUse = pCteUse;
148904 pCteUse->nUse++;
148905
148906 /* Check if this is a recursive CTE. */
148907 pRecTerm = pSel = pFrom->pSelect;
148908 bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
148909 while( bMayRecursive && pRecTerm->op==pSel->op ){
148910 int i;
148911 SrcList *pSrc = pRecTerm->pSrc;
148912 assert( pRecTerm->pPrior!=0 );
148913 for(i=0; i<pSrc->nSrc; i++){
148914 SrcItem *pItem = &pSrc->a[i];
148915 if( pItem->zDatabase==0
148916 && pItem->zName!=0
 
 
148917 && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
148918 ){
148919 pItem->pTab = pTab;
148920 pTab->nTabRef++;
148921 pItem->fg.isRecursive = 1;
148922 if( pRecTerm->selFlags & SF_Recursive ){
148923 sqlite3ErrorMsg(pParse,
148924 "multiple references to recursive table: %s", pCte->zName
@@ -149016,15 +149381,18 @@
149016 ** allocates and populates the SrcItem.pTab object. If successful,
149017 ** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
149018 ** SQLITE_NOMEM.
149019 */
149020 SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
149021 Select *pSel = pFrom->pSelect;
149022 Table *pTab;
149023
 
 
 
149024 assert( pSel );
149025 pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
149026 if( pTab==0 ) return SQLITE_NOMEM;
149027 pTab->nTabRef = 1;
149028 if( pFrom->zAlias ){
149029 pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
149030 }else{
@@ -149140,37 +149508,39 @@
149140 ** an entry of the FROM clause is a subquery instead of a table or view,
149141 ** then create a transient table structure to describe the subquery.
149142 */
149143 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149144 Table *pTab;
149145 assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
149146 if( pFrom->pTab ) continue;
149147 assert( pFrom->fg.isRecursive==0 );
149148 if( pFrom->zName==0 ){
149149 #ifndef SQLITE_OMIT_SUBQUERY
149150 Select *pSel = pFrom->pSelect;
 
 
149151 /* A sub-query in the FROM clause of a SELECT */
149152 assert( pSel!=0 );
149153 assert( pFrom->pTab==0 );
149154 if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
149155 if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
149156 #endif
149157 #ifndef SQLITE_OMIT_CTE
149158 }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
149159 if( rc>1 ) return WRC_Abort;
149160 pTab = pFrom->pTab;
149161 assert( pTab!=0 );
149162 #endif
149163 }else{
149164 /* An ordinary table or view name in the FROM clause */
149165 assert( pFrom->pTab==0 );
149166 pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
149167 if( pTab==0 ) return WRC_Abort;
149168 if( pTab->nTabRef>=0xffff ){
149169 sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
149170 pTab->zName);
149171 pFrom->pTab = 0;
149172 return WRC_Abort;
149173 }
149174 pTab->nTabRef++;
149175 if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
149176 return WRC_Abort;
@@ -149178,19 +149548,19 @@
149178 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
149179 if( !IsOrdinaryTable(pTab) ){
149180 i16 nCol;
149181 u8 eCodeOrig = pWalker->eCode;
149182 if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
149183 assert( pFrom->pSelect==0 );
149184 if( IsView(pTab) ){
149185 if( (db->flags & SQLITE_EnableView)==0
149186 && pTab->pSchema!=db->aDb[1].pSchema
149187 ){
149188 sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
149189 pTab->zName);
149190 }
149191 pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
149192 }
149193 #ifndef SQLITE_OMIT_VIRTUALTABLE
149194 else if( ALWAYS(IsVirtual(pTab))
149195 && pFrom->fg.fromDDL
149196 && ALWAYS(pTab->u.vtab.p!=0)
@@ -149202,11 +149572,13 @@
149202 assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
149203 #endif
149204 nCol = pTab->nCol;
149205 pTab->nCol = -1;
149206 pWalker->eCode = 1; /* Turn on Select.selId renumbering */
149207 sqlite3WalkSelect(pWalker, pFrom->pSelect);
 
 
149208 pWalker->eCode = eCodeOrig;
149209 pTab->nCol = nCol;
149210 }
149211 #endif
149212 }
@@ -149289,11 +149661,11 @@
149289 assert( ExprUseWOfst(pE) );
149290 iErrOfst = pE->w.iOfst;
149291 }
149292 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149293 int nAdd; /* Number of cols including rowid */
149294 Table *pTab = pFrom->pTab; /* Table for this data source */
149295 ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
149296 char *zTabName; /* AS name for this data source */
149297 const char *zSchemaName = 0; /* Schema name for this data source */
149298 int iDb; /* Schema index for this data src */
149299 IdList *pUsing; /* USING clause for pFrom[1] */
@@ -149300,14 +149672,15 @@
149300
149301 if( (zTabName = pFrom->zAlias)==0 ){
149302 zTabName = pTab->zName;
149303 }
149304 if( db->mallocFailed ) break;
149305 assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
149306 if( pFrom->fg.isNestedFrom ){
149307 assert( pFrom->pSelect!=0 );
149308 pNestedFrom = pFrom->pSelect->pEList;
 
149309 assert( pNestedFrom!=0 );
149310 assert( pNestedFrom->nExpr==pTab->nCol );
149311 assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
149312 }else{
149313 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
@@ -149542,18 +149915,16 @@
149542 p->selFlags |= SF_HasTypeInfo;
149543 pParse = pWalker->pParse;
149544 assert( (p->selFlags & SF_Resolved) );
149545 pTabList = p->pSrc;
149546 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149547 Table *pTab = pFrom->pTab;
149548 assert( pTab!=0 );
149549 if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
149550 /* A sub-query in the FROM clause of a SELECT */
149551 Select *pSel = pFrom->pSelect;
149552 if( pSel ){
149553 sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
149554 }
149555 }
149556 }
149557 }
149558 #endif
149559
@@ -149863,10 +150234,11 @@
149863 int i;
149864 struct AggInfo_func *pF;
149865 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
149866 ExprList *pList;
149867 assert( ExprUseXList(pF->pFExpr) );
 
149868 pList = pF->pFExpr->x.pList;
149869 if( pF->iOBTab>=0 ){
149870 /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
149871 ** were stored in emphermal table pF->iOBTab. Here, we extract those
149872 ** inputs (in ORDER BY order) and make all calls to OP_AggStep
@@ -150072,19 +150444,21 @@
150072 sqlite3ReleaseTempRange(pParse, regAgg, nArg);
150073 }
150074 if( addrNext ){
150075 sqlite3VdbeResolveLabel(v, addrNext);
150076 }
 
150077 }
150078 if( regHit==0 && pAggInfo->nAccumulator ){
150079 regHit = regAcc;
150080 }
150081 if( regHit ){
150082 addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
150083 }
150084 for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
150085 sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
 
150086 }
150087
150088 pAggInfo->directMode = 0;
150089 if( addrHitTest ){
150090 sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
@@ -150196,29 +150570,32 @@
150196 SrcList *pTabList, /* Search for self-joins in this FROM clause */
150197 SrcItem *pThis, /* Search for prior reference to this subquery */
150198 int iFirst, int iEnd /* Range of FROM-clause entries to search. */
150199 ){
150200 SrcItem *pItem;
150201 assert( pThis->pSelect!=0 );
150202 if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
 
 
 
150203 while( iFirst<iEnd ){
150204 Select *pS1;
150205 pItem = &pTabList->a[iFirst++];
150206 if( pItem->pSelect==0 ) continue;
150207 if( pItem->fg.viaCoroutine ) continue;
150208 if( pItem->zName==0 ) continue;
150209 assert( pItem->pTab!=0 );
150210 assert( pThis->pTab!=0 );
150211 if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue;
150212 if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
150213 pS1 = pItem->pSelect;
150214 if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
150215 /* The query flattener left two different CTE tables with identical
150216 ** names in the same FROM clause. */
150217 continue;
150218 }
150219 if( pItem->pSelect->selFlags & SF_PushDown ){
150220 /* The view was modified by some other optimization such as
150221 ** pushDownWhereTerms() */
150222 continue;
150223 }
150224 return pItem;
@@ -150258,10 +150635,11 @@
150258 static int countOfViewOptimization(Parse *pParse, Select *p){
150259 Select *pSub, *pPrior;
150260 Expr *pExpr;
150261 Expr *pCount;
150262 sqlite3 *db;
 
150263 if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
150264 if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
150265 if( p->pWhere ) return 0;
150266 if( p->pHaving ) return 0;
150267 if( p->pGroupBy ) return 0;
@@ -150272,30 +150650,30 @@
150272 if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
150273 assert( ExprUseXList(pExpr) );
150274 if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
150275 if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
150276 if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
150277 pSub = p->pSrc->a[0].pSelect;
150278 if( pSub==0 ) return 0; /* The FROM is a subquery */
 
150279 if( pSub->pPrior==0 ) return 0; /* Must be a compound */
150280 if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
150281 do{
150282 if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
150283 if( pSub->pWhere ) return 0; /* No WHERE clause */
150284 if( pSub->pLimit ) return 0; /* No LIMIT clause */
150285 if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
150286 assert( pSub->pHaving==0 ); /* Due to the previous */
150287 pSub = pSub->pPrior; /* Repeat over compound */
150288 }while( pSub );
150289
150290 /* If we reach this point then it is OK to perform the transformation */
150291
150292 db = pParse->db;
150293 pCount = pExpr;
150294 pExpr = 0;
150295 pSub = p->pSrc->a[0].pSelect;
150296 p->pSrc->a[0].pSelect = 0;
150297 sqlite3SrcListDelete(db, p->pSrc);
150298 p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
150299 while( pSub ){
150300 Expr *pTerm;
150301 pPrior = pSub->pPrior;
@@ -150336,16 +150714,16 @@
150336 static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
150337 int i;
150338 for(i=0; i<pSrc->nSrc; i++){
150339 SrcItem *p1 = &pSrc->a[i];
150340 if( p1==p0 ) continue;
150341 if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
150342 return 1;
150343 }
150344 if( p1->pSelect
150345 && (p1->pSelect->selFlags & SF_NestedFrom)!=0
150346 && sameSrcAlias(p0, p1->pSelect->pSrc)
150347 ){
150348 return 1;
150349 }
150350 }
150351 return 0;
@@ -150406,17 +150784,17 @@
150406 while( 1 /*exit-by-break*/ ){
150407 if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
150408 if( i==0 ) break;
150409 i--;
150410 pItem--;
150411 if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
150412 }
150413 return 1;
150414 }
150415
150416 /*
150417 ** Generate code for the SELECT statement given in the p argument.
150418 **
150419 ** The results are returned according to the SelectDest structure.
150420 ** See comments in sqliteInt.h for further information.
150421 **
150422 ** This routine returns the number of errors. If any errors are
@@ -150423,10 +150801,44 @@
150423 ** encountered, then an appropriate error message is left in
150424 ** pParse->zErrMsg.
150425 **
150426 ** This routine does NOT free the Select structure passed in. The
150427 ** calling function needs to do that.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150428 */
150429 SQLITE_PRIVATE int sqlite3Select(
150430 Parse *pParse, /* The parser context */
150431 Select *p, /* The SELECT statement being coded. */
150432 SelectDest *pDest /* What to do with the query results */
@@ -150466,10 +150878,11 @@
150466 }
150467 sqlite3ShowSelect(p);
150468 }
150469 #endif
150470
 
150471 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
150472 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
150473 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
150474 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
150475 if( IgnorableDistinct(pDest) ){
@@ -150517,11 +150930,11 @@
150517 if( p->selFlags & SF_UFSrcCheck ){
150518 SrcItem *p0 = &p->pSrc->a[0];
150519 if( sameSrcAlias(p0, p->pSrc) ){
150520 sqlite3ErrorMsg(pParse,
150521 "target object/alias may not appear in FROM clause: %s",
150522 p0->zAlias ? p0->zAlias : p0->pTab->zName
150523 );
150524 goto select_end;
150525 }
150526
150527 /* Clear the SF_UFSrcCheck flag. The check has already been performed,
@@ -150552,16 +150965,17 @@
150552 memset(&sSort, 0, sizeof(sSort));
150553 sSort.pOrderBy = p->pOrderBy;
150554
150555 /* Try to do various optimizations (flattening subqueries, and strength
150556 ** reduction of join operators) in the FROM clause up into the main query
 
150557 */
150558 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150559 for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
150560 SrcItem *pItem = &pTabList->a[i];
150561 Select *pSub = pItem->pSelect;
150562 Table *pTab = pItem->pTab;
150563
150564 /* The expander should have already created transient Table objects
150565 ** even for FROM clause elements such as subqueries that do not correspond
150566 ** to a real table */
150567 assert( pTab!=0 );
@@ -150574,10 +150988,11 @@
150574 **
150575 ** If terms of the i-th table are used in the WHERE clause in such a
150576 ** way that the i-th table cannot be the NULL row of a join, then
150577 ** perform the appropriate simplification. This is called
150578 ** "OUTER JOIN strength reduction" in the SQLite documentation.
 
150579 */
150580 if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
150581 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
150582 pItem->fg.jointype & JT_LTORJ)
150583 && OptimizationEnabled(db, SQLITE_SimplifyJoin)
@@ -150644,11 +151059,12 @@
150644 ** flattening in that case.
150645 */
150646 if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
150647 assert( pSub->pGroupBy==0 );
150648
150649 /* If a FROM-clause subquery has an ORDER BY clause that is not
 
150650 ** really doing anything, then delete it now so that it does not
150651 ** interfere with query flattening. See the discussion at
150652 ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
150653 **
150654 ** Beware of these cases where the ORDER BY clause may not be safely
@@ -150710,10 +151126,11 @@
150710 || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0)
150711 ){
150712 continue;
150713 }
150714
 
150715 if( flattenSubquery(pParse, p, i, isAgg) ){
150716 if( pParse->nErr ) goto select_end;
150717 /* This subquery can be absorbed into its parent. */
150718 i = -1;
150719 }
@@ -150725,11 +151142,11 @@
150725 }
150726 #endif
150727
150728 #ifndef SQLITE_OMIT_COMPOUND_SELECT
150729 /* Handle compound SELECT statements using the separate multiSelect()
150730 ** procedure.
150731 */
150732 if( p->pPrior ){
150733 rc = multiSelect(pParse, p, pDest);
150734 #if TREETRACE_ENABLED
150735 TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
@@ -150741,13 +151158,13 @@
150741 return rc;
150742 }
150743 #endif
150744
150745 /* Do the WHERE-clause constant propagation optimization if this is
150746 ** a join. No need to speed time on this operation for non-join queries
150747 ** as the equivalent optimization will be handled by query planner in
150748 ** sqlite3WhereBegin().
150749 */
150750 if( p->pWhere!=0
150751 && p->pWhere->op==TK_AND
150752 && OptimizationEnabled(db, SQLITE_PropagateConst)
150753 && propagateConstants(pParse, p)
@@ -150760,31 +151177,38 @@
150760 #endif
150761 }else{
150762 TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
150763 }
150764
 
150765 if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
150766 && countOfViewOptimization(pParse, p)
150767 ){
150768 if( db->mallocFailed ) goto select_end;
150769 pTabList = p->pSrc;
150770 }
150771
150772 /* For each term in the FROM clause, do two things:
150773 ** (1) Authorized unreferenced tables
150774 ** (2) Generate code for all sub-queries
 
 
 
150775 */
150776 for(i=0; i<pTabList->nSrc; i++){
150777 SrcItem *pItem = &pTabList->a[i];
150778 SrcItem *pPrior;
150779 SelectDest dest;
 
150780 Select *pSub;
150781 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150782 const char *zSavedAuthContext;
150783 #endif
150784
150785 /* Issue SQLITE_READ authorizations with a fake column name for any
 
 
150786 ** tables that are referenced but from which no values are extracted.
150787 ** Examples of where these kinds of null SQLITE_READ authorizations
150788 ** would occur:
150789 **
150790 ** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
@@ -150797,21 +151221,32 @@
150797 ** which would be unambiguous. But legacy authorization callbacks might
150798 ** assume the column name is non-NULL and segfault. The use of an empty
150799 ** string for the fake column name seems safer.
150800 */
150801 if( pItem->colUsed==0 && pItem->zName!=0 ){
150802 sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
 
 
 
 
 
 
 
 
 
150803 }
150804
150805 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150806 /* Generate code for all sub-queries in the FROM clause
150807 */
150808 pSub = pItem->pSelect;
150809 if( pSub==0 || pItem->addrFillSub!=0 ) continue;
 
 
150810
150811 /* The code for a subquery should only be generated once. */
150812 assert( pItem->addrFillSub==0 );
150813
150814 /* Increment Parse.nHeight by the height of the largest expression
150815 ** tree referred to by this, the parent select. The child select
150816 ** may contain expression trees of at most
150817 ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
@@ -150820,10 +151255,11 @@
150820 */
150821 pParse->nHeight += sqlite3SelectExprHeight(p);
150822
150823 /* Make copies of constant WHERE-clause terms in the outer query down
150824 ** inside the subquery. This can help the subquery to run more efficiently.
 
150825 */
150826 if( OptimizationEnabled(db, SQLITE_PushDown)
150827 && (pItem->fg.isCte==0
150828 || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
150829 && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
@@ -150833,17 +151269,18 @@
150833 TREETRACE(0x4000,pParse,p,
150834 ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
150835 sqlite3TreeViewSelect(0, p, 0);
150836 }
150837 #endif
150838 assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
150839 }else{
150840 TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
150841 }
150842
150843 /* Convert unused result columns of the subquery into simple NULL
150844 ** expressions, to avoid unneeded searching and computation.
 
150845 */
150846 if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
150847 && disableUnusedSubqueryResultColumns(pItem)
150848 ){
150849 #if TREETRACE_ENABLED
@@ -150857,64 +151294,70 @@
150857 }
150858
150859 zSavedAuthContext = pParse->zAuthContext;
150860 pParse->zAuthContext = pItem->zName;
150861
150862 /* Generate code to implement the subquery
150863 */
150864 if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
150865 /* Implement a co-routine that will return a single row of the result
150866 ** set on each invocation.
150867 */
150868 int addrTop = sqlite3VdbeCurrentAddr(v)+1;
150869
150870 pItem->regReturn = ++pParse->nMem;
150871 sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
150872 VdbeComment((v, "%!S", pItem));
150873 pItem->addrFillSub = addrTop;
150874 sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
150875 ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
150876 sqlite3Select(pParse, pSub, &dest);
150877 pItem->pTab->nRowLogEst = pSub->nSelectRow;
150878 pItem->fg.viaCoroutine = 1;
150879 pItem->regResult = dest.iSdst;
150880 sqlite3VdbeEndCoroutine(v, pItem->regReturn);
 
150881 sqlite3VdbeJumpHere(v, addrTop-1);
150882 sqlite3ClearTempRegCache(pParse);
150883 }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
150884 /* This is a CTE for which materialization code has already been
150885 ** generated. Invoke the subroutine to compute the materialization,
150886 ** the make the pItem->iCursor be a copy of the ephemeral table that
150887 ** holds the result of the materialization. */
150888 CteUse *pCteUse = pItem->u2.pCteUse;
150889 sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
150890 if( pItem->iCursor!=pCteUse->iCur ){
150891 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
150892 VdbeComment((v, "%!S", pItem));
150893 }
150894 pSub->nSelectRow = pCteUse->nRowEst;
150895 }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
150896 /* This view has already been materialized by a prior entry in
150897 ** this same FROM clause. Reuse it. */
150898 if( pPrior->addrFillSub ){
150899 sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
 
 
 
 
 
150900 }
150901 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
150902 pSub->nSelectRow = pPrior->pSelect->nSelectRow;
150903 }else{
150904 /* Materialize the view. If the view is not correlated, generate a
150905 ** subroutine to do the materialization so that subsequent uses of
150906 ** the same view can reuse the materialization. */
150907 int topAddr;
150908 int onceAddr = 0;
150909 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
150910 int addrExplain;
150911 #endif
150912
150913 pItem->regReturn = ++pParse->nMem;
150914 topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
150915 pItem->addrFillSub = topAddr+1;
150916 pItem->fg.isMaterialized = 1;
150917 if( pItem->fg.isCorrelated==0 ){
150918 /* If the subquery is not correlated and if we are not inside of
150919 ** a trigger, then we only need to compute the value of the subquery
150920 ** once. */
@@ -150925,21 +151368,21 @@
150925 }
150926 sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
150927
150928 ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
150929 sqlite3Select(pParse, pSub, &dest);
150930 pItem->pTab->nRowLogEst = pSub->nSelectRow;
150931 if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
150932 sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
150933 VdbeComment((v, "end %!S", pItem));
150934 sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
150935 sqlite3VdbeJumpHere(v, topAddr);
150936 sqlite3ClearTempRegCache(pParse);
150937 if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
150938 CteUse *pCteUse = pItem->u2.pCteUse;
150939 pCteUse->addrM9e = pItem->addrFillSub;
150940 pCteUse->regRtn = pItem->regReturn;
150941 pCteUse->iCur = pItem->iCursor;
150942 pCteUse->nRowEst = pSub->nSelectRow;
150943 }
150944 }
150945 if( db->mallocFailed ) goto select_end;
@@ -150961,11 +151404,13 @@
150961 TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
150962 sqlite3TreeViewSelect(0, p, 0);
150963 }
150964 #endif
150965
150966 /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
 
 
150967 ** if the select-list is the same as the ORDER BY list, then this query
150968 ** can be rewritten as a GROUP BY. In other words, this:
150969 **
150970 ** SELECT DISTINCT xyz FROM ... ORDER BY xyz
150971 **
@@ -151011,11 +151456,11 @@
151011 ** do the sorting. But this sorting ephemeral index might end up
151012 ** being unused if the data can be extracted in pre-sorted order.
151013 ** If that is the case, then the OP_OpenEphemeral instruction will be
151014 ** changed to an OP_Noop once we figure out that the sorting index is
151015 ** not needed. The sSort.addrSortIndex variable is used to facilitate
151016 ** that change.
151017 */
151018 if( sSort.pOrderBy ){
151019 KeyInfo *pKeyInfo;
151020 pKeyInfo = sqlite3KeyInfoFromExprList(
151021 pParse, sSort.pOrderBy, 0, pEList->nExpr);
@@ -151028,10 +151473,11 @@
151028 }else{
151029 sSort.addrSortIndex = -1;
151030 }
151031
151032 /* If the output is destined for a temporary table, open that table.
 
151033 */
151034 if( pDest->eDest==SRT_EphemTab ){
151035 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
151036 if( p->selFlags & SF_NestedFrom ){
151037 /* Delete or NULL-out result columns that will never be used */
@@ -151045,11 +151491,11 @@
151045 if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
151046 }
151047 }
151048 }
151049
151050 /* Set the limiter.
151051 */
151052 iEnd = sqlite3VdbeMakeLabel(pParse);
151053 if( (p->selFlags & SF_FixedLimit)==0 ){
151054 p->nSelectRow = 320; /* 4 billion rows */
151055 }
@@ -151057,11 +151503,11 @@
151057 if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
151058 sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
151059 sSort.sortFlags |= SORTFLAG_UseSorter;
151060 }
151061
151062 /* Open an ephemeral index to use for the distinct set.
151063 */
151064 if( p->selFlags & SF_Distinct ){
151065 sDistinct.tabTnct = pParse->nTab++;
151066 sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
151067 sDistinct.tabTnct, 0, 0,
@@ -151072,11 +151518,11 @@
151072 }else{
151073 sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
151074 }
151075
151076 if( !isAgg && pGroupBy==0 ){
151077 /* No aggregate functions and no GROUP BY clause */
151078 u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
151079 | (p->selFlags & SF_FixedLimit);
151080 #ifndef SQLITE_OMIT_WINDOWFUNC
151081 Window *pWin = p->pWin; /* Main window object (or NULL) */
151082 if( pWin ){
@@ -151145,12 +151591,12 @@
151145 */
151146 TREETRACE(0x2,pParse,p,("WhereEnd\n"));
151147 sqlite3WhereEnd(pWInfo);
151148 }
151149 }else{
151150 /* This case when there exist aggregate functions or a GROUP BY clause
151151 ** or both */
151152 NameContext sNC; /* Name context for processing aggregate information */
151153 int iAMem; /* First Mem address for storing current GROUP BY */
151154 int iBMem; /* First Mem address for previous GROUP BY */
151155 int iUseFlag; /* Mem address holding flag indicating that at least
151156 ** one row of the input to the aggregator has been
@@ -151265,11 +151711,11 @@
151265 }
151266 #endif
151267
151268
151269 /* Processing for aggregates with GROUP BY is very different and
151270 ** much more complex than aggregates without a GROUP BY.
151271 */
151272 if( pGroupBy ){
151273 KeyInfo *pKeyInfo; /* Keying information for the group by clause */
151274 int addr1; /* A-vs-B comparison jump */
151275 int addrOutputRow; /* Start of subroutine that outputs a result row */
@@ -151562,13 +152008,16 @@
151562 struct AggInfo_func *pF = &pAggInfo->aFunc[0];
151563 fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
151564 }
151565 } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
151566 else {
 
151567 Table *pTab;
151568 if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
151569 /* If isSimpleCount() returns a pointer to a Table structure, then
 
 
151570 ** the SQL statement is of the form:
151571 **
151572 ** SELECT count(*) FROM <tbl>
151573 **
151574 ** where the Table structure returned represents table <tbl>.
@@ -151623,10 +152072,12 @@
151623 assignAggregateRegisters(pParse, pAggInfo);
151624 sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
151625 sqlite3VdbeAddOp1(v, OP_Close, iCsr);
151626 explainSimpleCount(pParse, pTab, pBest);
151627 }else{
 
 
151628 int regAcc = 0; /* "populate accumulators" flag */
151629 ExprList *pDistinct = 0;
151630 u16 distFlag = 0;
151631 int eDist;
151632
@@ -151711,11 +152162,11 @@
151711 if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
151712 explainTempTable(pParse, "DISTINCT");
151713 }
151714
151715 /* If there is an ORDER BY clause, then we need to sort the results
151716 ** and send them to the callback one by one.
151717 */
151718 if( sSort.pOrderBy ){
151719 assert( p->pEList==pEList );
151720 generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
151721 }
@@ -151734,10 +152185,11 @@
151734 select_end:
151735 assert( db->mallocFailed==0 || db->mallocFailed==1 );
151736 assert( db->mallocFailed==0 || pParse->nErr!=0 );
151737 sqlite3ExprListDelete(db, pMinMaxOrderBy);
151738 #ifdef SQLITE_DEBUG
 
151739 if( pAggInfo && !db->mallocFailed ){
151740 #if TREETRACE_ENABLED
151741 if( sqlite3TreeTrace & 0x20 ){
151742 TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
151743 printAggInfo(pAggInfo);
@@ -152123,12 +152575,14 @@
152123 **
152124 ** To maintain backwards compatibility, ignore the database
152125 ** name on pTableName if we are reparsing out of the schema table
152126 */
152127 if( db->init.busy && iDb!=1 ){
152128 sqlite3DbFree(db, pTableName->a[0].zDatabase);
152129 pTableName->a[0].zDatabase = 0;
 
 
152130 }
152131
152132 /* If the trigger name was unqualified, and the table is a temp table,
152133 ** then set iDb to 1 to create the trigger in the temporary database.
152134 ** If sqlite3SrcListLookup() returns 0, indicating the table does not
@@ -152602,11 +153056,12 @@
152602 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
152603 goto drop_trigger_cleanup;
152604 }
152605
152606 assert( pName->nSrc==1 );
152607 zDb = pName->a[0].zDatabase;
 
152608 zName = pName->a[0].zName;
152609 assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
152610 for(i=OMIT_TEMPDB; i<db->nDb; i++){
152611 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
152612 if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
@@ -152839,11 +153294,13 @@
152839 assert( zName || pSrc==0 );
152840 if( pSrc ){
152841 Schema *pSchema = pStep->pTrig->pSchema;
152842 pSrc->a[0].zName = zName;
152843 if( pSchema!=db->aDb[1].pSchema ){
152844 pSrc->a[0].pSchema = pSchema;
 
 
152845 }
152846 if( pStep->pFrom ){
152847 SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
152848 if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
152849 Select *pSubquery;
@@ -152952,11 +153409,11 @@
152952 SrcList *pSrc;
152953 assert( pSelect!=0 );
152954 pSrc = pSelect->pSrc;
152955 assert( pSrc!=0 );
152956 for(i=0; i<pSrc->nSrc; i++){
152957 if( pSrc->a[i].pTab==pWalker->u.pTab ){
152958 testcase( pSelect->selFlags & SF_Correlated );
152959 pSelect->selFlags |= SF_Correlated;
152960 pWalker->eCode = 1;
152961 break;
152962 }
@@ -153023,11 +153480,11 @@
153023 memset(&sSelect, 0, sizeof(sSelect));
153024 memset(&sFrom, 0, sizeof(sFrom));
153025 sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
153026 sSelect.pSrc = &sFrom;
153027 sFrom.nSrc = 1;
153028 sFrom.a[0].pTab = pTab;
153029 sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
153030 sFrom.a[0].iCursor = -1;
153031 sqlite3SelectPrep(pParse, &sSelect, 0);
153032 if( pParse->nErr==0 ){
153033 assert( db->mallocFailed==0 );
@@ -153734,11 +154191,11 @@
153734 ExprList *pList = 0;
153735 ExprList *pGrp = 0;
153736 Expr *pLimit2 = 0;
153737 ExprList *pOrderBy2 = 0;
153738 sqlite3 *db = pParse->db;
153739 Table *pTab = pTabList->a[0].pTab;
153740 SrcList *pSrc;
153741 Expr *pWhere2;
153742 int eDest;
153743
153744 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -153758,12 +154215,12 @@
153758
153759 assert( pTabList->nSrc>1 );
153760 if( pSrc ){
153761 assert( pSrc->a[0].fg.notCte );
153762 pSrc->a[0].iCursor = -1;
153763 pSrc->a[0].pTab->nTabRef--;
153764 pSrc->a[0].pTab = 0;
153765 }
153766 if( pPk ){
153767 for(i=0; i<pPk->nKeyCol; i++){
153768 Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
153769 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -155007,11 +155464,11 @@
155007 NameContext sNC; /* Context for resolving symbolic names */
155008 Expr sCol[2]; /* Index column converted into an Expr */
155009 int nClause = 0; /* Counter of ON CONFLICT clauses */
155010
155011 assert( pTabList->nSrc==1 );
155012 assert( pTabList->a[0].pTab!=0 );
155013 assert( pUpsert!=0 );
155014 assert( pUpsert->pUpsertTarget!=0 );
155015
155016 /* Resolve all symbolic names in the conflict-target clause, which
155017 ** includes both the list of columns and the optional partial-index
@@ -155026,11 +155483,11 @@
155026 if( rc ) return rc;
155027 rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
155028 if( rc ) return rc;
155029
155030 /* Check to see if the conflict target matches the rowid. */
155031 pTab = pTabList->a[0].pTab;
155032 pTarget = pUpsert->pUpsertTarget;
155033 iCursor = pTabList->a[0].iCursor;
155034 if( HasRowid(pTab)
155035 && pTarget->nExpr==1
155036 && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
@@ -155397,10 +155854,13 @@
155397 int nRes; /* Bytes of reserved space at the end of each page */
155398 int nDb; /* Number of attached databases */
155399 const char *zDbMain; /* Schema name of database to vacuum */
155400 const char *zOut; /* Name of output file */
155401 u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
 
 
 
155402
155403 if( !db->autoCommit ){
155404 sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
155405 return SQLITE_ERROR; /* IMP: R-12218-18073 */
155406 }
@@ -155437,31 +155897,33 @@
155437
155438 zDbMain = db->aDb[iDb].zDbSName;
155439 pMain = db->aDb[iDb].pBt;
155440 isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
155441
155442 /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
155443 ** can be set to 'off' for this file, as it is not recovered if a crash
155444 ** occurs anyway. The integrity of the database is maintained by a
155445 ** (possibly synchronous) transaction opened on the main database before
155446 ** sqlite3BtreeCopyFile() is called.
155447 **
155448 ** An optimization would be to use a non-journaled pager.
155449 ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
155450 ** that actually made the VACUUM run slower. Very little journalling
155451 ** actually occurs when doing a vacuum since the vacuum_db is initially
155452 ** empty. Only the journal header is written. Apparently it takes more
155453 ** time to parse and run the PRAGMA to turn journalling off than it does
155454 ** to write the journal header file.
155455 */
 
 
155456 nDb = db->nDb;
155457 rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
155458 db->openFlags = saved_openFlags;
155459 if( rc!=SQLITE_OK ) goto end_of_vacuum;
155460 assert( (db->nDb-1)==nDb );
155461 pDb = &db->aDb[nDb];
155462 assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
155463 pTemp = pDb->pBt;
155464 if( pOut ){
155465 sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
155466 i64 sz = 0;
155467 if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
@@ -155534,15 +155996,15 @@
155534 /* Loop through the tables in the main database. For each, do
155535 ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
155536 ** the contents to the temporary database.
155537 */
155538 rc = execSqlF(db, pzErrMsg,
155539 "SELECT'INSERT INTO vacuum_db.'||quote(name)"
155540 "||' SELECT*FROM\"%w\".'||quote(name)"
155541 "FROM vacuum_db.sqlite_schema "
155542 "WHERE type='table'AND coalesce(rootpage,1)>0",
155543 zDbMain
155544 );
155545 assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
155546 db->mDbFlags &= ~DBFLAG_Vacuum;
155547 if( rc!=SQLITE_OK ) goto end_of_vacuum;
155548
@@ -155550,15 +156012,15 @@
155550 ** over to the temporary database. None of these objects has any
155551 ** associated storage, so all we have to do is copy their entries
155552 ** from the schema table.
155553 */
155554 rc = execSqlF(db, pzErrMsg,
155555 "INSERT INTO vacuum_db.sqlite_schema"
155556 " SELECT*FROM \"%w\".sqlite_schema"
155557 " WHERE type IN('view','trigger')"
155558 " OR(type='table'AND rootpage=0)",
155559 zDbMain
155560 );
155561 if( rc ) goto end_of_vacuum;
155562
155563 /* At this point, there is a write transaction open on both the
155564 ** vacuum database and the main database. Assuming no error occurs,
@@ -157198,10 +157660,11 @@
157198 } btree;
157199 struct { /* Information for virtual tables */
157200 int idxNum; /* Index number */
157201 u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
157202 u32 bOmitOffset : 1; /* True to let virtual table handle offset */
 
157203 i8 isOrdered; /* True if satisfies ORDER BY */
157204 u16 omitMask; /* Terms that may be omitted */
157205 char *idxStr; /* Index identifier string */
157206 u32 mHandleIn; /* Terms to handle as IN(...) instead of == */
157207 } vtab;
@@ -157832,11 +158295,11 @@
157832 Index *pIdx;
157833
157834 assert( pLoop->u.btree.pIndex!=0 );
157835 pIdx = pLoop->u.btree.pIndex;
157836 assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
157837 if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
157838 if( isSearch ){
157839 zFmt = "PRIMARY KEY";
157840 }
157841 }else if( flags & WHERE_PARTIALIDX ){
157842 zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
@@ -157875,11 +158338,13 @@
157875 }
157876 sqlite3_str_appendf(&str, "%c?)", cRangeOp);
157877 }
157878 #ifndef SQLITE_OMIT_VIRTUALTABLE
157879 else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
157880 sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
 
 
157881 pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
157882 }
157883 #endif
157884 if( pItem->fg.jointype & JT_LEFT ){
157885 sqlite3_str_appendf(&str, " LEFT-JOIN");
@@ -157929,11 +158394,11 @@
157929 sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
157930 str.printfFlags = SQLITE_PRINTF_INTERNAL;
157931 sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
157932 pLoop = pLevel->pWLoop;
157933 if( pLoop->wsFlags & WHERE_IPK ){
157934 const Table *pTab = pItem->pTab;
157935 if( pTab->iPKey>=0 ){
157936 sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
157937 }else{
157938 sqlite3_str_appendf(&str, "rowid=?");
157939 }
@@ -157992,11 +158457,13 @@
157992 }
157993 if( wsFlags & WHERE_INDEXED ){
157994 sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
157995 }
157996 }else{
157997 int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
 
 
157998 VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
157999 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158000 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158001 sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158002 }
@@ -159129,11 +159596,12 @@
159129 pLoop = pLevel->pWLoop;
159130 pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
159131 iCur = pTabItem->iCursor;
159132 pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
159133 bRev = (pWInfo->revMask>>iLevel)&1;
159134 VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
 
159135 #if WHERETRACE_ENABLED /* 0x4001 */
159136 if( sqlite3WhereTrace & 0x1 ){
159137 sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
159138 iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
159139 if( sqlite3WhereTrace & 0x1000 ){
@@ -159184,15 +159652,19 @@
159184 }
159185 addrHalt = pWInfo->a[j].addrBrk;
159186
159187 /* Special case of a FROM clause subquery implemented as a co-routine */
159188 if( pTabItem->fg.viaCoroutine ){
159189 int regYield = pTabItem->regReturn;
159190 sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
 
 
 
 
159191 pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
159192 VdbeCoverage(v);
159193 VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
159194 pLevel->op = OP_Goto;
159195 }else
159196
159197 #ifndef SQLITE_OMIT_VIRTUALTABLE
159198 if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
@@ -159917,11 +160389,11 @@
159917 int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */
159918 int iRetInit; /* Address of regReturn init */
159919 int untestedTerms = 0; /* Some terms not completely tested */
159920 int ii; /* Loop counter */
159921 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
159922 Table *pTab = pTabItem->pTab;
159923
159924 pTerm = pLoop->aLTerm[0];
159925 assert( pTerm!=0 );
159926 assert( pTerm->eOperator & WO_OR );
159927 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
@@ -160376,11 +160848,11 @@
160376 /* pTab is the right-hand table of the RIGHT JOIN. Generate code that
160377 ** will record that the current row of that table has been matched at
160378 ** least once. This is accomplished by storing the PK for the row in
160379 ** both the iMatch index and the regBloom Bloom filter.
160380 */
160381 pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
160382 if( HasRowid(pTab) ){
160383 r = sqlite3GetTempRange(pParse, 2);
160384 sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
160385 nPk = 1;
160386 }else{
@@ -160483,23 +160955,27 @@
160483 SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
160484 SrcList sFrom;
160485 Bitmask mAll = 0;
160486 int k;
160487
160488 ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
160489 sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
160490 pRJ->regReturn);
160491 for(k=0; k<iLevel; k++){
160492 int iIdxCur;
160493 SrcItem *pRight;
160494 assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
160495 pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
160496 mAll |= pWInfo->a[k].pWLoop->maskSelf;
160497 if( pRight->fg.viaCoroutine ){
 
 
 
 
160498 sqlite3VdbeAddOp3(
160499 v, OP_Null, 0, pRight->regResult,
160500 pRight->regResult + pRight->pSelect->pEList->nExpr-1
160501 );
160502 }
160503 sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
160504 iIdxCur = pWInfo->a[k].iIdxCur;
160505 if( iIdxCur ){
@@ -160533,11 +161009,11 @@
160533 int iCur = pLevel->iTabCur;
160534 int r = ++pParse->nMem;
160535 int nPk;
160536 int jmp;
160537 int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
160538 Table *pTab = pTabItem->pTab;
160539 if( HasRowid(pTab) ){
160540 sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
160541 nPk = 1;
160542 }else{
160543 int iPk;
@@ -160785,15 +161261,24 @@
160785 assert( !ExprHasProperty(pRight, EP_IntValue) );
160786 z = (u8*)pRight->u.zToken;
160787 }
160788 if( z ){
160789
160790 /* Count the number of prefix characters prior to the first wildcard */
 
 
 
 
160791 cnt = 0;
160792 while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
160793 cnt++;
160794 if( c==wc[3] && z[cnt]!=0 ) cnt++;
 
 
 
 
 
160795 }
160796
160797 /* The optimization is possible only if (1) the pattern does not begin
160798 ** with a wildcard and if (2) the non-wildcard prefix does not end with
160799 ** an (illegal 0xff) character, or (3) the pattern does not consist of
@@ -160804,11 +161289,11 @@
160804 ** removed. */
160805 if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
160806 Expr *pPrefix;
160807
160808 /* A "complete" match if the pattern ends with "*" or "%" */
160809 *pisComplete = c==wc[0] && z[cnt+1]==0;
160810
160811 /* Get the pattern prefix. Remove all escapes from the prefix. */
160812 pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
160813 if( pPrefix ){
160814 int iFrom, iTo;
@@ -161523,11 +162008,13 @@
161523 mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere);
161524 mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving);
161525 if( ALWAYS(pSrc!=0) ){
161526 int i;
161527 for(i=0; i<pSrc->nSrc; i++){
161528 mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
 
 
161529 if( pSrc->a[i].fg.isUsing==0 ){
161530 mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
161531 }
161532 if( pSrc->a[i].fg.isTabFunc ){
161533 mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
@@ -161561,11 +162048,11 @@
161561 Index *pIdx;
161562 int i;
161563 int iCur;
161564 do{
161565 iCur = pFrom->a[j].iCursor;
161566 for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
161567 if( pIdx->aColExpr==0 ) continue;
161568 for(i=0; i<pIdx->nKeyCol; i++){
161569 if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
161570 assert( pIdx->bHasExpr );
161571 if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
@@ -161605,11 +162092,11 @@
161605 return 1;
161606 }
161607
161608 for(i=0; i<pFrom->nSrc; i++){
161609 Index *pIdx;
161610 for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
161611 if( pIdx->aColExpr ){
161612 return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
161613 }
161614 }
161615 }
@@ -162193,11 +162680,11 @@
162193 */
162194 SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
162195 assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
162196 if( p->pGroupBy==0
162197 && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
162198 && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
162199 ){
162200 ExprList *pOrderBy = p->pOrderBy;
162201 int iCsr = p->pSrc->a[0].iCursor;
162202 int ii;
162203
@@ -162414,11 +162901,11 @@
162414 int j, k;
162415 ExprList *pArgs;
162416 Expr *pColRef;
162417 Expr *pTerm;
162418 if( pItem->fg.isTabFunc==0 ) return;
162419 pTab = pItem->pTab;
162420 assert( pTab!=0 );
162421 pArgs = pItem->u1.pFuncArg;
162422 if( pArgs==0 ) return;
162423 for(j=k=0; j<pArgs->nExpr; j++){
162424 Expr *pRhs;
@@ -163098,11 +163585,11 @@
163098 /* If there is more than one table or sub-select in the FROM clause of
163099 ** this query, then it will not be possible to show that the DISTINCT
163100 ** clause is redundant. */
163101 if( pTabList->nSrc!=1 ) return 0;
163102 iBase = pTabList->a[0].iCursor;
163103 pTab = pTabList->a[0].pTab;
163104
163105 /* If any of the expressions is an IPK column on table iBase, then return
163106 ** true. Note: The (p->iTable==iBase) part of this test may be false if the
163107 ** current SELECT is a correlated sub-query.
163108 */
@@ -163362,14 +163849,14 @@
163362 }
163363 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
163364 assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
163365 leftCol = pTerm->u.x.leftColumn;
163366 if( leftCol<0 ) return 0;
163367 aff = pSrc->pTab->aCol[leftCol].affinity;
163368 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
163369 testcase( pTerm->pExpr->op==TK_IS );
163370 return columnIsGoodIndexCandidate(pSrc->pTab, leftCol);
163371 }
163372 #endif
163373
163374
163375 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -163473,11 +163960,11 @@
163473 /* Count the number of columns that will be added to the index
163474 ** and used to match WHERE clause constraints */
163475 nKeyCol = 0;
163476 pTabList = pWC->pWInfo->pTabList;
163477 pSrc = &pTabList->a[pLevel->iFrom];
163478 pTable = pSrc->pTab;
163479 pWCEnd = &pWC->a[pWC->nTerm];
163480 pLoop = pLevel->pWLoop;
163481 idxCols = 0;
163482 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
163483 Expr *pExpr = pTerm->pExpr;
@@ -163615,16 +164102,21 @@
163615 }
163616
163617 /* Fill the automatic index with content */
163618 assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
163619 if( pSrc->fg.viaCoroutine ){
163620 int regYield = pSrc->regReturn;
 
 
 
 
 
163621 addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
163622 sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
163623 addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
163624 VdbeCoverage(v);
163625 VdbeComment((v, "next row of %s", pSrc->pTab->zName));
163626 }else{
163627 addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
163628 }
163629 if( pPartial ){
163630 iContinue = sqlite3VdbeMakeLabel(pParse);
@@ -163642,15 +164134,16 @@
163642 sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v));
163643 sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
163644 sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
163645 if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
163646 if( pSrc->fg.viaCoroutine ){
 
163647 sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
163648 testcase( pParse->db->mallocFailed );
163649 assert( pLevel->iIdxCur>0 );
163650 translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
163651 pSrc->regResult, pLevel->iIdxCur);
163652 sqlite3VdbeGoto(v, addrTop);
163653 pSrc->fg.viaCoroutine = 0;
163654 }else{
163655 sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
163656 sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -163737,11 +164230,11 @@
163737 */
163738 pTabList = pWInfo->pTabList;
163739 iSrc = pLevel->iFrom;
163740 pItem = &pTabList->a[iSrc];
163741 assert( pItem!=0 );
163742 pTab = pItem->pTab;
163743 assert( pTab!=0 );
163744 sz = sqlite3LogEstToInt(pTab->nRowLogEst);
163745 if( sz<10000 ){
163746 sz = 10000;
163747 }else if( sz>10000000 ){
@@ -163768,11 +164261,11 @@
163768 Index *pIdx = pLoop->u.btree.pIndex;
163769 int n = pLoop->u.btree.nEq;
163770 int r1 = sqlite3GetTempRange(pParse, n);
163771 int jj;
163772 for(jj=0; jj<n; jj++){
163773 assert( pIdx->pTable==pItem->pTab );
163774 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
163775 }
163776 sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
163777 sqlite3ReleaseTempRange(pParse, r1, n);
163778 }
@@ -163849,11 +164342,11 @@
163849 int eDistinct = 0;
163850 ExprList *pOrderBy = pWInfo->pOrderBy;
163851 WhereClause *p;
163852
163853 assert( pSrc!=0 );
163854 pTab = pSrc->pTab;
163855 assert( pTab!=0 );
163856 assert( IsVirtual(pTab) );
163857
163858 /* Find all WHERE clause constraints referring to this virtual table.
163859 ** Mark each term with the TERM_OK flag. Set nTerm to the number of
@@ -164857,11 +165350,11 @@
164857 SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
164858 if( pWC ){
164859 WhereInfo *pWInfo = pWC->pWInfo;
164860 int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
164861 SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
164862 Table *pTab = pItem->pTab;
164863 Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
164864 sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
164865 p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
164866 sqlite3DebugPrintf(" %12s",
164867 pItem->zAlias ? pItem->zAlias : pTab->zName);
@@ -165845,19 +166338,19 @@
165845 ** 1. The cost of doing one search-by-key to find the first matching
165846 ** entry
165847 ** 2. Stepping forward in the index pNew->nOut times to find all
165848 ** additional matching entries.
165849 */
165850 assert( pSrc->pTab->szTabRow>0 );
165851 if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
165852 /* The pProbe->szIdxRow is low for an IPK table since the interior
165853 ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
165854 ** But the leaf pages are full-size, so pProbe->szIdxRow would badly
165855 ** under-estimate the scanning cost. */
165856 rCostIdx = pNew->nOut + 16;
165857 }else{
165858 rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
165859 }
165860 rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
165861
165862 /* Estimate the cost of running the loop. If all data is coming
165863 ** from the index, then this is just the cost of doing the index
@@ -166318,13 +166811,13 @@
166318
166319 pNew = pBuilder->pNew;
166320 pWInfo = pBuilder->pWInfo;
166321 pTabList = pWInfo->pTabList;
166322 pSrc = pTabList->a + pNew->iTab;
166323 pTab = pSrc->pTab;
166324 pWC = pBuilder->pWC;
166325 assert( !IsVirtual(pSrc->pTab) );
166326
166327 if( pSrc->fg.isIndexedBy ){
166328 assert( pSrc->fg.isCte==0 );
166329 /* An INDEXED BY clause specifies a particular index to use */
166330 pProbe = pSrc->u2.pIBIndex;
@@ -166345,11 +166838,11 @@
166345 sPk.pTable = pTab;
166346 sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
166347 sPk.idxType = SQLITE_IDXTYPE_IPK;
166348 aiRowEstPk[0] = pTab->nRowLogEst;
166349 aiRowEstPk[1] = 0;
166350 pFirst = pSrc->pTab->pIndex;
166351 if( pSrc->fg.notIndexed==0 ){
166352 /* The real indices of the table are only considered if the
166353 ** NOT INDEXED qualifier is omitted from the FROM clause */
166354 sPk.pNext = pFirst;
166355 }
@@ -166435,10 +166928,11 @@
166435 pNew->iSortIdx = 0;
166436 pNew->rSetup = 0;
166437 pNew->prereq = mPrereq;
166438 pNew->nOut = rSize;
166439 pNew->u.btree.pIndex = pProbe;
 
166440 b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
166441
166442 /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
166443 assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
166444 if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
@@ -166464,13 +166958,13 @@
166464 #else
166465 pNew->rRun = rSize + 16;
166466 #endif
166467 ApplyCostMultiplier(pNew->rRun, pTab->costMult);
166468 whereLoopOutputAdjust(pWC, pNew, rSize);
166469 if( pSrc->pSelect ){
166470 if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
166471 pNew->u.btree.pOrderBy = pSrc->pSelect->pOrderBy;
166472 }
166473 rc = whereLoopInsert(pBuilder, pNew);
166474 pNew->nOut = rSize;
166475 if( rc ) break;
166476 }else{
@@ -166692,11 +167186,11 @@
166692 pIdxInfo->estimatedRows = 25;
166693 pIdxInfo->idxFlags = 0;
166694 pHidden->mHandleIn = 0;
166695
166696 /* Invoke the virtual table xBestIndex() method */
166697 rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
166698 if( rc ){
166699 if( rc==SQLITE_CONSTRAINT ){
166700 /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
166701 ** that the particular combination of parameters provided is unusable.
166702 ** Make no entries in the loop table.
@@ -166722,11 +167216,11 @@
166722 || j<0
166723 || (pTerm = termFromWhereClause(pWC, j))==0
166724 || pNew->aLTerm[iTerm]!=0
166725 || pIdxCons->usable==0
166726 ){
166727 sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
166728 freeIdxStr(pIdxInfo);
166729 return SQLITE_ERROR;
166730 }
166731 testcase( iTerm==nConstraint-1 );
166732 testcase( j==0 );
@@ -166785,11 +167279,11 @@
166785 pNew->nLTerm = mxTerm+1;
166786 for(i=0; i<=mxTerm; i++){
166787 if( pNew->aLTerm[i]==0 ){
166788 /* The non-zero argvIdx values must be contiguous. Raise an
166789 ** error if they are not */
166790 sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
166791 freeIdxStr(pIdxInfo);
166792 return SQLITE_ERROR;
166793 }
166794 }
166795 assert( pNew->nLTerm<=pNew->nLSlot );
@@ -166797,10 +167291,11 @@
166797 pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
166798 pIdxInfo->needToFreeIdxStr = 0;
166799 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
166800 pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
166801 pIdxInfo->nOrderBy : 0);
 
166802 pNew->rSetup = 0;
166803 pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
166804 pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
166805
166806 /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
@@ -166987,11 +167482,11 @@
166987 pWInfo = pBuilder->pWInfo;
166988 pParse = pWInfo->pParse;
166989 pWC = pBuilder->pWC;
166990 pNew = pBuilder->pNew;
166991 pSrc = &pWInfo->pTabList->a[pNew->iTab];
166992 assert( IsVirtual(pSrc->pTab) );
166993 p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
166994 if( p==0 ) return SQLITE_NOMEM_BKPT;
166995 pNew->rSetup = 0;
166996 pNew->wsFlags = WHERE_VIRTUALTABLE;
166997 pNew->nLTerm = 0;
@@ -167001,11 +167496,11 @@
167001 freeIndexInfo(pParse->db, p);
167002 return SQLITE_NOMEM_BKPT;
167003 }
167004
167005 /* First call xBestIndex() with all constraints usable. */
167006 WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
167007 WHERETRACE(0x800, (" VirtualOne: all usable\n"));
167008 rc = whereLoopAddVirtualOne(
167009 pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
167010 );
167011 if( bRetry ){
@@ -167083,11 +167578,11 @@
167083 pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
167084 }
167085 }
167086
167087 freeIndexInfo(pParse->db, p);
167088 WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
167089 return rc;
167090 }
167091 #endif /* SQLITE_OMIT_VIRTUALTABLE */
167092
167093 /*
@@ -167155,11 +167650,11 @@
167155 if( sqlite3WhereTrace & 0x20000 ){
167156 sqlite3WhereClausePrint(sSubBuild.pWC);
167157 }
167158 #endif
167159 #ifndef SQLITE_OMIT_VIRTUALTABLE
167160 if( IsVirtual(pItem->pTab) ){
167161 rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
167162 }else
167163 #endif
167164 {
167165 rc = whereLoopAddBtree(&sSubBuild, mPrereq);
@@ -167269,11 +167764,11 @@
167269 bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0;
167270 }else if( !hasRightJoin ){
167271 mPrereq = 0;
167272 }
167273 #ifndef SQLITE_OMIT_VIRTUALTABLE
167274 if( IsVirtual(pItem->pTab) ){
167275 SrcItem *p;
167276 for(p=&pItem[1]; p<pEnd; p++){
167277 if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
167278 mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
167279 }
@@ -167905,11 +168400,11 @@
167905 rDelta = 15*(nDep-3);
167906 #ifdef WHERETRACE_ENABLED /* 0x4 */
167907 if( sqlite3WhereTrace&0x4 ){
167908 SrcItem *pItem = pWInfo->pTabList->a + iLoop;
167909 sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
167910 pItem->zAlias ? pItem->zAlias : pItem->pTab->zName,
167911 nDep, rDelta);
167912 }
167913 #endif
167914 if( pWInfo->nOutStarDelta==0 ){
167915 for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
@@ -168455,11 +168950,11 @@
168455
168456 pWInfo = pBuilder->pWInfo;
168457 if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
168458 assert( pWInfo->pTabList->nSrc>=1 );
168459 pItem = pWInfo->pTabList->a;
168460 pTab = pItem->pTab;
168461 if( IsVirtual(pTab) ) return 0;
168462 if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
168463 testcase( pItem->fg.isIndexedBy );
168464 testcase( pItem->fg.notIndexed );
168465 return 0;
@@ -168718,11 +169213,11 @@
168718 assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
168719 for(i=0; i<pWInfo->nLevel; i++){
168720 WhereLoop *pLoop = pWInfo->a[i].pWLoop;
168721 const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
168722 SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
168723 Table *pTab = pItem->pTab;
168724 if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
168725 pTab->tabFlags |= TF_MaybeReanalyze;
168726 if( i>=1
168727 && (pLoop->wsFlags & reqFlags)==reqFlags
168728 /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
@@ -168875,12 +169370,12 @@
168875 int ii;
168876 for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
168877 SrcItem *pItem = &pWInfo->pTabList->a[ii];
168878 if( !pItem->fg.isCte
168879 || pItem->u2.pCteUse->eM10d!=M10d_Yes
168880 || NEVER(pItem->pSelect==0)
168881 || pItem->pSelect->pOrderBy==0
168882 ){
168883 pWInfo->revMask |= MASKBIT(ii);
168884 }
168885 }
168886 }
@@ -169366,19 +169861,19 @@
169366 */
169367 assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
169368 if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
169369 int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
169370 int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
169371 assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
169372 if( bOnerow || (
169373 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
169374 && !IsVirtual(pTabList->a[0].pTab)
169375 && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
169376 && OptimizationEnabled(db, SQLITE_OnePass)
169377 )){
169378 pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
169379 if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
169380 if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
169381 bFordelete = OPFLAG_FORDELETE;
169382 }
169383 pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
169384 }
@@ -169392,11 +169887,11 @@
169392 Table *pTab; /* Table to open */
169393 int iDb; /* Index of database containing table/index */
169394 SrcItem *pTabItem;
169395
169396 pTabItem = &pTabList->a[pLevel->iFrom];
169397 pTab = pTabItem->pTab;
169398 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
169399 pLoop = pLevel->pWLoop;
169400 if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
169401 /* Do nothing */
169402 }else
@@ -169463,11 +169958,11 @@
169463 /* This is one term of an OR-optimization using the PRIMARY KEY of a
169464 ** WITHOUT ROWID table. No need for a separate index */
169465 iIndexCur = pLevel->iTabCur;
169466 op = 0;
169467 }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
169468 Index *pJ = pTabItem->pTab->pIndex;
169469 iIndexCur = iAuxArg;
169470 assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
169471 while( ALWAYS(pJ) && pJ!=pIx ){
169472 iIndexCur++;
169473 pJ = pJ->pNext;
@@ -169530,11 +170025,11 @@
169530 pRJ->iMatch = pParse->nTab++;
169531 pRJ->regBloom = ++pParse->nMem;
169532 sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
169533 pRJ->regReturn = ++pParse->nMem;
169534 sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
169535 assert( pTab==pTabItem->pTab );
169536 if( HasRowid(pTab) ){
169537 KeyInfo *pInfo;
169538 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
169539 pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
169540 if( pInfo ){
@@ -169569,17 +170064,22 @@
169569 if( pParse->nErr ) goto whereBeginError;
169570 pLevel = &pWInfo->a[ii];
169571 wsFlags = pLevel->pWLoop->wsFlags;
169572 pSrc = &pTabList->a[pLevel->iFrom];
169573 if( pSrc->fg.isMaterialized ){
169574 if( pSrc->fg.isCorrelated ){
169575 sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
 
 
 
 
169576 }else{
169577 int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
169578 sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
169579 sqlite3VdbeJumpHere(v, iOnce);
169580 }
 
 
 
169581 }
169582 assert( pTabList == pWInfo->pTabList );
169583 if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
169584 if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
169585 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -169788,13 +170288,14 @@
169788 if( (ws & WHERE_IDX_ONLY)==0 ){
169789 SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
169790 assert( pLevel->iTabCur==pSrc->iCursor );
169791 if( pSrc->fg.viaCoroutine ){
169792 int m, n;
169793 n = pSrc->regResult;
169794 assert( pSrc->pTab!=0 );
169795 m = pSrc->pTab->nCol;
 
169796 sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
169797 }
169798 sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
169799 }
169800 if( (ws & WHERE_INDEXED)
@@ -169814,20 +170315,20 @@
169814 sqlite3VdbeGoto(v, pLevel->addrFirst);
169815 }
169816 sqlite3VdbeJumpHere(v, addr);
169817 }
169818 VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
169819 pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
169820 }
169821
169822 assert( pWInfo->nLevel<=pTabList->nSrc );
169823 for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
169824 int k, last;
169825 VdbeOp *pOp, *pLastOp;
169826 Index *pIdx = 0;
169827 SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
169828 Table *pTab = pTabItem->pTab;
169829 assert( pTab!=0 );
169830 pLoop = pLevel->pWLoop;
169831
169832 /* Do RIGHT JOIN processing. Generate code that will output the
169833 ** unmatched rows of the right operand of the RIGHT JOIN with
@@ -169842,13 +170343,14 @@
169842 ** the co-routine into OP_Copy of result contained in a register.
169843 ** OP_Rowid becomes OP_Null.
169844 */
169845 if( pTabItem->fg.viaCoroutine ){
169846 testcase( pParse->db->mallocFailed );
169847 assert( pTabItem->regResult>=0 );
 
169848 translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
169849 pTabItem->regResult, 0);
169850 continue;
169851 }
169852
169853 /* If this scan uses an index, make VDBE code substitutions to read data
169854 ** from the index instead of from the table where possible. In some cases
@@ -171054,13 +171556,14 @@
171054 p->selId, p));
171055 p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
171056 assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
171057 ** of sqlite3DbMallocRawNN() called from
171058 ** sqlite3SrcListAppend() */
171059 if( p->pSrc ){
 
 
171060 Table *pTab2;
171061 p->pSrc->a[0].pSelect = pSub;
171062 p->pSrc->a[0].fg.isCorrelated = 1;
171063 sqlite3SrcListAssignCursors(pParse, p->pSrc);
171064 pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
171065 pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
171066 pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -171070,20 +171573,18 @@
171070 ** the correct error message regardless. */
171071 rc = SQLITE_NOMEM;
171072 }else{
171073 memcpy(pTab, pTab2, sizeof(Table));
171074 pTab->tabFlags |= TF_Ephemeral;
171075 p->pSrc->a[0].pTab = pTab;
171076 pTab = pTab2;
171077 memset(&w, 0, sizeof(w));
171078 w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
171079 w.xSelectCallback = sqlite3WalkerDepthIncrease;
171080 w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
171081 sqlite3WalkSelect(&w, pSub);
171082 }
171083 }else{
171084 sqlite3SelectDelete(db, pSub);
171085 }
171086 if( db->mallocFailed ) rc = SQLITE_NOMEM;
171087
171088 /* Defer deleting the temporary table pTab because if an error occurred,
171089 ** there could still be references to that table embedded in the
@@ -171366,14 +171867,19 @@
171366 ** This is called by code in select.c before it calls sqlite3WhereBegin()
171367 ** to begin iterating through the sub-query results. It is used to allocate
171368 ** and initialize registers and cursors used by sqlite3WindowCodeStep().
171369 */
171370 SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
171371 int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
171372 Window *pMWin = pSelect->pWin;
171373 Window *pWin;
171374 Vdbe *v = sqlite3GetVdbe(pParse);
 
 
 
 
 
 
 
171375
171376 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
171377 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
171378 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
171379 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
@@ -172766,11 +173272,11 @@
172766 Window *pMWin = p->pWin;
172767 ExprList *pOrderBy = pMWin->pOrderBy;
172768 Vdbe *v = sqlite3GetVdbe(pParse);
172769 int csrWrite; /* Cursor used to write to eph. table */
172770 int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
172771 int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
172772 int iInput; /* To iterate through sub cols */
172773 int addrNe; /* Address of OP_Ne */
172774 int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
172775 int addrInteger = 0; /* Address of OP_Integer */
172776 int addrEmpty; /* Address of OP_Rewind in flush: */
@@ -177217,24 +177723,33 @@
177217 }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
177218 yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
177219 if( yymsp[-5].minor.yy203 ){
177220 SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
177221 SrcItem *pOld = yymsp[-3].minor.yy203->a;
 
177222 pNew->zName = pOld->zName;
177223 pNew->zDatabase = pOld->zDatabase;
177224 pNew->pSelect = pOld->pSelect;
177225 if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
177226 pNew->fg.isNestedFrom = 1;
 
 
 
 
 
 
 
 
 
177227 }
177228 if( pOld->fg.isTabFunc ){
177229 pNew->u1.pFuncArg = pOld->u1.pFuncArg;
177230 pOld->u1.pFuncArg = 0;
177231 pOld->fg.isTabFunc = 0;
177232 pNew->fg.isTabFunc = 1;
177233 }
177234 pOld->zName = pOld->zDatabase = 0;
177235 pOld->pSelect = 0;
177236 }
177237 sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
177238 }else{
177239 Select *pSubquery;
177240 sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
@@ -182324,11 +182839,12 @@
182324 }
182325
182326 assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
182327 assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
182328 extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
182329 SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
 
182330 enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
182331
182332 /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
182333 ** the meaning is inverted. So flip the bit. */
182334 assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
@@ -184790,10 +185306,22 @@
184790 case SQLITE_TESTCTRL_OPTIMIZATIONS: {
184791 sqlite3 *db = va_arg(ap, sqlite3*);
184792 db->dbOptFlags = va_arg(ap, u32);
184793 break;
184794 }
 
 
 
 
 
 
 
 
 
 
 
 
184795
184796 /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
184797 **
184798 ** If parameter onoff is 1, subsequent calls to localtime() fail.
184799 ** If 2, then invoke xAlt() instead of localtime(). If 0, normal
@@ -224464,10 +224992,11 @@
224464 )
224465 ){
224466 pIdxInfo->orderByConsumed = 1;
224467 pIdxInfo->idxNum |= 0x08;
224468 }
 
224469
224470 return SQLITE_OK;
224471 }
224472
224473 /*
@@ -232374,13 +232903,36 @@
232374 ** It is the output of the tokenizer module. For tokendata=1 tables, this
232375 ** includes any embedded 0x00 and trailing data.
232376 **
232377 ** This API can be quite slow if used with an FTS5 table created with the
232378 ** "detail=none" or "detail=column" option.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232379 */
232380 struct Fts5ExtensionApi {
232381 int iVersion; /* Currently always set to 3 */
232382
232383 void *(*xUserData)(Fts5Context*);
232384
232385 int (*xColumnCount)(Fts5Context*);
232386 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -232418,10 +232970,19 @@
232418 int (*xQueryToken)(Fts5Context*,
232419 int iPhrase, int iToken,
232420 const char **ppToken, int *pnToken
232421 );
232422 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
 
 
 
 
 
 
 
 
 
232423 };
232424
232425 /*
232426 ** CUSTOM AUXILIARY FUNCTIONS
232427 *************************************************************************/
@@ -232430,19 +232991,20 @@
232430 ** CUSTOM TOKENIZERS
232431 **
232432 ** Applications may also register custom tokenizer types. A tokenizer
232433 ** is registered by providing fts5 with a populated instance of the
232434 ** following structure. All structure methods must be defined, setting
 
232435 ** any member of the fts5_tokenizer struct to NULL leads to undefined
232436 ** behaviour. The structure methods are expected to function as follows:
232437 **
232438 ** xCreate:
232439 ** This function is used to allocate and initialize a tokenizer instance.
232440 ** A tokenizer instance is required to actually tokenize text.
232441 **
232442 ** The first argument passed to this function is a copy of the (void*)
232443 ** pointer provided by the application when the fts5_tokenizer object
232444 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
232445 ** The second and third arguments are an array of nul-terminated strings
232446 ** containing the tokenizer arguments, if any, specified following the
232447 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
232448 ** to create the FTS5 table.
@@ -232462,11 +233024,11 @@
232462 ** This function is expected to tokenize the nText byte string indicated
232463 ** by argument pText. pText may or may not be nul-terminated. The first
232464 ** argument passed to this function is a pointer to an Fts5Tokenizer object
232465 ** returned by an earlier call to xCreate().
232466 **
232467 ** The second argument indicates the reason that FTS5 is requesting
232468 ** tokenization of the supplied text. This is always one of the following
232469 ** four values:
232470 **
232471 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
232472 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -232485,10 +233047,17 @@
232485 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
232486 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
232487 ** function. Or an fts5_api.xColumnSize() request made by the same
232488 ** on a columnsize=0 database.
232489 ** </ul>
 
 
 
 
 
 
 
232490 **
232491 ** For each token in the input string, the supplied callback xToken() must
232492 ** be invoked. The first argument to it should be a copy of the pointer
232493 ** passed as the second argument to xTokenize(). The third and fourth
232494 ** arguments are a pointer to a buffer containing the token text, and the
@@ -232508,10 +233077,34 @@
232508 ** immediately return a copy of the xToken() return value. Or, if the
232509 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
232510 ** if an error occurs with the xTokenize() implementation itself, it
232511 ** may abandon the tokenization and return any error code other than
232512 ** SQLITE_OK or SQLITE_DONE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232513 **
232514 ** SYNONYM SUPPORT
232515 **
232516 ** Custom tokenizers may also support synonyms. Consider a case in which a
232517 ** user wishes to query for a phrase such as "first place". Using the
@@ -232617,10 +233210,37 @@
232617 ** provide synonyms when tokenizing document text (method (3)) or query
232618 ** text (method (2)), not both. Doing so will not cause any errors, but is
232619 ** inefficient.
232620 */
232621 typedef struct Fts5Tokenizer Fts5Tokenizer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232622 typedef struct fts5_tokenizer fts5_tokenizer;
232623 struct fts5_tokenizer {
232624 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
232625 void (*xDelete)(Fts5Tokenizer*);
232626 int (*xTokenize)(Fts5Tokenizer*,
@@ -232635,10 +233255,11 @@
232635 int iStart, /* Byte offset of token within input text */
232636 int iEnd /* Byte offset of end of token within input text */
232637 )
232638 );
232639 };
 
232640
232641 /* Flags that may be passed as the third argument to xTokenize() */
232642 #define FTS5_TOKENIZE_QUERY 0x0001
232643 #define FTS5_TOKENIZE_PREFIX 0x0002
232644 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -232655,11 +233276,11 @@
232655 /*************************************************************************
232656 ** FTS5 EXTENSION REGISTRATION API
232657 */
232658 typedef struct fts5_api fts5_api;
232659 struct fts5_api {
232660 int iVersion; /* Currently always set to 2 */
232661
232662 /* Create a new tokenizer */
232663 int (*xCreateTokenizer)(
232664 fts5_api *pApi,
232665 const char *zName,
@@ -232682,10 +233303,29 @@
232682 const char *zName,
232683 void *pUserData,
232684 fts5_extension_function xFunction,
232685 void (*xDestroy)(void*)
232686 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232687 };
232688
232689 /*
232690 ** END OF REGISTRATION API
232691 *************************************************************************/
@@ -232858,14 +233498,17 @@
232858 typedef struct Fts5Config Fts5Config;
232859 typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
232860
232861 struct Fts5TokenizerConfig {
232862 Fts5Tokenizer *pTok;
232863 fts5_tokenizer *pTokApi;
 
232864 const char **azArg;
232865 int nArg;
232866 int ePattern; /* FTS_PATTERN_XXX constant */
 
 
232867 };
232868
232869 /*
232870 ** An instance of the following structure encodes all information that can
232871 ** be gleaned from the CREATE VIRTUAL TABLE statement.
@@ -232902,10 +233545,12 @@
232902 ** This is only used for debugging. If set to false, any prefix indexes
232903 ** are ignored. This value is configured using:
232904 **
232905 ** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
232906 **
 
 
232907 */
232908 struct Fts5Config {
232909 sqlite3 *db; /* Database handle */
232910 Fts5Global *pGlobal; /* Global fts5 object for handle db */
232911 char *zDb; /* Database holding FTS index (e.g. "main") */
@@ -232919,14 +233564,16 @@
232919 int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
232920 char *zContent; /* content table */
232921 char *zContentRowid; /* "content_rowid=" option value */
232922 int bColumnsize; /* "columnsize=" option value (dflt==1) */
232923 int bTokendata; /* "tokendata=" option value (dflt==0) */
 
232924 int eDetail; /* FTS5_DETAIL_XXX value */
232925 char *zContentExprlist;
232926 Fts5TokenizerConfig t;
232927 int bLock; /* True when table is preparing statement */
 
232928
232929 /* Values loaded from the %_config table */
232930 int iVersion; /* fts5 file format 'version' */
232931 int iCookie; /* Incremented when %_config is modified */
232932 int pgsz; /* Approximate page size used in %_data */
@@ -232988,10 +233635,12 @@
232988 /* Set the value of a single config attribute */
232989 static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
232990
232991 static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
232992
 
 
232993 /*
232994 ** End of interface to code in fts5_config.c.
232995 **************************************************************************/
232996
232997 /**************************************************************************
@@ -233032,11 +233681,11 @@
233032
233033 /* Write and decode big-endian 32-bit integer values */
233034 static void sqlite3Fts5Put32(u8*, int);
233035 static int sqlite3Fts5Get32(const u8*);
233036
233037 #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
233038 #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
233039
233040 typedef struct Fts5PoslistReader Fts5PoslistReader;
233041 struct Fts5PoslistReader {
233042 /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
@@ -233323,10 +233972,21 @@
233323
233324 static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
233325
233326 static int sqlite3Fts5FlushToDisk(Fts5Table*);
233327
 
 
 
 
 
 
 
 
 
 
 
233328 /*
233329 ** End of interface to code in fts5.c.
233330 **************************************************************************/
233331
233332 /**************************************************************************
@@ -233402,11 +234062,11 @@
233402 static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
233403
233404 static int sqlite3Fts5DropAll(Fts5Config*);
233405 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
233406
233407 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
233408 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
233409 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
233410
233411 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
233412
@@ -233428,10 +234088,13 @@
233428 static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
233429 static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
233430 static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
233431 static int sqlite3Fts5StorageReset(Fts5Storage *p);
233432
 
 
 
233433 /*
233434 ** End of interface to code in fts5_storage.c.
233435 **************************************************************************/
233436
233437
@@ -235357,10 +236020,11 @@
235357 p->iOff = iEndOff;
235358 }
235359
235360 return rc;
235361 }
 
235362
235363 /*
235364 ** Implementation of highlight() function.
235365 */
235366 static void fts5HighlightFunction(
@@ -235388,16 +236052,23 @@
235388 rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
235389 if( rc==SQLITE_RANGE ){
235390 sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
235391 rc = SQLITE_OK;
235392 }else if( ctx.zIn ){
 
 
235393 if( rc==SQLITE_OK ){
235394 rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
235395 }
235396
235397 if( rc==SQLITE_OK ){
235398 rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
 
 
 
 
 
235399 }
235400 if( ctx.bOpen ){
235401 fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
235402 }
235403 fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
@@ -235590,19 +236261,23 @@
235590 }
235591
235592 memset(&sFinder, 0, sizeof(Fts5SFinder));
235593 for(i=0; i<nCol; i++){
235594 if( iCol<0 || iCol==i ){
 
 
235595 int nDoc;
235596 int nDocsize;
235597 int ii;
235598 sFinder.iPos = 0;
235599 sFinder.nFirst = 0;
235600 rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
235601 if( rc!=SQLITE_OK ) break;
235602 rc = pApi->xTokenize(pFts,
235603 sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
 
 
235604 );
235605 if( rc!=SQLITE_OK ) break;
235606 rc = pApi->xColumnSize(pFts, i, &nDocsize);
235607 if( rc!=SQLITE_OK ) break;
235608
@@ -235656,10 +236331,13 @@
235656 }
235657 if( rc==SQLITE_OK && nColSize==0 ){
235658 rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
235659 }
235660 if( ctx.zIn ){
 
 
 
235661 if( rc==SQLITE_OK ){
235662 rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
235663 }
235664
235665 ctx.iRangeStart = iBestStart;
@@ -235674,11 +236352,16 @@
235674 while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
235675 rc = fts5CInstIterNext(&ctx.iter);
235676 }
235677
235678 if( rc==SQLITE_OK ){
235679 rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
 
 
 
 
 
235680 }
235681 if( ctx.bOpen ){
235682 fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
235683 }
235684 if( ctx.iRangeEnd>=(nColSize-1) ){
@@ -235857,21 +236540,69 @@
235857 sqlite3_result_double(pCtx, -1.0 * score);
235858 }else{
235859 sqlite3_result_error_code(pCtx, rc);
235860 }
235861 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235862
235863 static int sqlite3Fts5AuxInit(fts5_api *pApi){
235864 struct Builtin {
235865 const char *zFunc; /* Function name (nul-terminated) */
235866 void *pUserData; /* User-data pointer */
235867 fts5_extension_function xFunc;/* Callback function */
235868 void (*xDestroy)(void*); /* Destructor function */
235869 } aBuiltin [] = {
235870 { "snippet", 0, fts5SnippetFunction, 0 },
235871 { "highlight", 0, fts5HighlightFunction, 0 },
235872 { "bm25", 0, fts5Bm25Function, 0 },
 
235873 };
235874 int rc = SQLITE_OK; /* Return code */
235875 int i; /* To iterate through builtin functions */
235876
235877 for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
@@ -236677,10 +237408,20 @@
236677 }else{
236678 pConfig->bColumnsize = (zArg[0]=='1');
236679 }
236680 return rc;
236681 }
 
 
 
 
 
 
 
 
 
 
236682
236683 if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
236684 const Fts5Enum aDetail[] = {
236685 { "none", FTS5_DETAIL_NONE },
236686 { "full", FTS5_DETAIL_FULL },
@@ -236967,11 +237708,15 @@
236967 */
236968 static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
236969 if( pConfig ){
236970 int i;
236971 if( pConfig->t.pTok ){
236972 pConfig->t.pTokApi->xDelete(pConfig->t.pTok);
 
 
 
 
236973 }
236974 sqlite3_free((char*)pConfig->t.azArg);
236975 sqlite3_free(pConfig->zDb);
236976 sqlite3_free(pConfig->zName);
236977 for(i=0; i<pConfig->nCol; i++){
@@ -237050,13 +237795,19 @@
237050 if( pText ){
237051 if( pConfig->t.pTok==0 ){
237052 rc = sqlite3Fts5LoadTokenizer(pConfig);
237053 }
237054 if( rc==SQLITE_OK ){
237055 rc = pConfig->t.pTokApi->xTokenize(
237056 pConfig->t.pTok, pCtx, flags, pText, nText, xToken
237057 );
 
 
 
 
 
 
237058 }
237059 }
237060 return rc;
237061 }
237062
@@ -237309,26 +238060,46 @@
237309 if( rc==SQLITE_OK
237310 && iVersion!=FTS5_CURRENT_VERSION
237311 && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
237312 ){
237313 rc = SQLITE_ERROR;
237314 if( pConfig->pzErrmsg ){
237315 assert( 0==*pConfig->pzErrmsg );
237316 *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
237317 "(found %d, expected %d or %d) - run 'rebuild'",
237318 iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
237319 );
237320 }
237321 }else{
237322 pConfig->iVersion = iVersion;
237323 }
237324
237325 if( rc==SQLITE_OK ){
237326 pConfig->iCookie = iCookie;
237327 }
237328 return rc;
237329 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237330
237331 /*
237332 ** 2014 May 31
237333 **
237334 ** The author disclaims copyright to this source code. In place of
@@ -237614,15 +238385,16 @@
237614 t = fts5ExprGetToken(&sParse, &z, &token);
237615 sqlite3Fts5Parser(pEngine, t, token, &sParse);
237616 }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
237617 sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
237618
 
237619 assert_expr_depth_ok(sParse.rc, sParse.pExpr);
237620
237621 /* If the LHS of the MATCH expression was a user column, apply the
237622 ** implicit column-filter. */
237623 if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
237624 int n = sizeof(Fts5Colset);
237625 Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
237626 if( pColset ){
237627 pColset->nCol = 1;
237628 pColset->aiCol[0] = iCol;
@@ -237635,19 +238407,11 @@
237635 *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
237636 if( pNew==0 ){
237637 sParse.rc = SQLITE_NOMEM;
237638 sqlite3Fts5ParseNodeFree(sParse.pExpr);
237639 }else{
237640 if( !sParse.pExpr ){
237641 const int nByte = sizeof(Fts5ExprNode);
237642 pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
237643 if( pNew->pRoot ){
237644 pNew->pRoot->bEof = 1;
237645 }
237646 }else{
237647 pNew->pRoot = sParse.pExpr;
237648 }
237649 pNew->pIndex = 0;
237650 pNew->pConfig = pConfig;
237651 pNew->apExprPhrase = sParse.apPhrase;
237652 pNew->nPhrase = sParse.nPhrase;
237653 pNew->bDesc = 0;
@@ -238461,11 +239225,11 @@
238461 pNode->bEof = 1;
238462 return rc;
238463 }
238464 }else{
238465 Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
238466 if( pIter->iRowid==iLast || pIter->bEof ) continue;
238467 bMatch = 0;
238468 if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
238469 return rc;
238470 }
238471 }
@@ -238983,13 +239747,10 @@
238983 ){
238984 const int SZALLOC = 8;
238985 Fts5ExprNearset *pRet = 0;
238986
238987 if( pParse->rc==SQLITE_OK ){
238988 if( pPhrase==0 ){
238989 return pNear;
238990 }
238991 if( pNear==0 ){
238992 sqlite3_int64 nByte;
238993 nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
238994 pRet = sqlite3_malloc64(nByte);
238995 if( pRet==0 ){
@@ -243382,11 +244143,11 @@
243382 iOff = 4;
243383 }
243384
243385 if( iOff<pIter->iEndofDoclist ){
243386 /* Next entry is on the current page */
243387 i64 iDelta;
243388 iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
243389 pIter->iLeafOffset = iOff;
243390 pIter->iRowid += iDelta;
243391 }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
243392 if( pIter->pSeg ){
@@ -250372,15 +251133,32 @@
250372
250373 /*
250374 ** Each tokenizer module registered with the FTS5 module is represented
250375 ** by an object of the following type. All such objects are stored as part
250376 ** of the Fts5Global.pTok list.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250377 */
250378 struct Fts5TokenizerModule {
250379 char *zName; /* Name of tokenizer */
250380 void *pUserData; /* User pointer passed to xCreate() */
250381 fts5_tokenizer x; /* Tokenizer functions */
 
 
250382 void (*xDestroy)(void*); /* Destructor function */
250383 Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
250384 };
250385
250386 struct Fts5FullTable {
@@ -250464,11 +251242,11 @@
250464
250465 /* Auxiliary data storage */
250466 Fts5Auxiliary *pAux; /* Currently executing extension function */
250467 Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
250468
250469 /* Cache used by auxiliary functions xInst() and xInstCount() */
250470 Fts5PoslistReader *aInstIter; /* One for each phrase */
250471 int nInstAlloc; /* Size of aInst[] array (entries / 3) */
250472 int nInstCount; /* Number of phrase instances */
250473 int *aInst; /* 3 integers per phrase instance */
250474 };
@@ -250499,10 +251277,16 @@
250499 #define FTS5CSR_REQUIRE_POSLIST 0x40
250500
250501 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
250502 #define BitFlagTest(x,y) (((x) & (y))!=0)
250503
 
 
 
 
 
 
250504
250505 /*
250506 ** Macros to Set(), Clear() and Test() cursor flags.
250507 */
250508 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -250673,12 +251457,11 @@
250673 rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
250674 }
250675
250676 /* Load the initial configuration */
250677 if( rc==SQLITE_OK ){
250678 rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
250679 sqlite3Fts5IndexRollback(pTab->p.pIndex);
250680 }
250681
250682 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
250683 rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
250684 }
@@ -250876,11 +251659,11 @@
250876 }else{
250877 if( iCol==nCol+1 ){
250878 if( bSeenRank ) continue;
250879 idxStr[iIdxStr++] = 'r';
250880 bSeenRank = 1;
250881 }else if( iCol>=0 ){
250882 nSeenMatch++;
250883 idxStr[iIdxStr++] = 'M';
250884 sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
250885 idxStr += strlen(&idxStr[iIdxStr]);
250886 assert( idxStr[iIdxStr]=='\0' );
@@ -251262,11 +252045,11 @@
251262 rc = SQLITE_NOMEM;
251263 }else{
251264 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
251265 SQLITE_PREPARE_PERSISTENT, &pRet, 0);
251266 if( rc!=SQLITE_OK ){
251267 *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
251268 }
251269 sqlite3_free(zSql);
251270 }
251271
251272 va_end(ap);
@@ -251497,10 +252280,192 @@
251497 sqlite3_free(p->p.base.zErrMsg);
251498 p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
251499 va_end(ap);
251500 }
251501
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251502
251503 /*
251504 ** This is the xFilter interface for the virtual table. See
251505 ** the virtual table xFilter method documentation for additional
251506 ** information.
@@ -251532,17 +252497,11 @@
251532 char **pzErrmsg = pConfig->pzErrmsg;
251533 int i;
251534 int iIdxStr = 0;
251535 Fts5Expr *pExpr = 0;
251536
251537 if( pConfig->bLock ){
251538 pTab->p.base.zErrMsg = sqlite3_mprintf(
251539 "recursively defined fts5 content table"
251540 );
251541 return SQLITE_ERROR;
251542 }
251543
251544 if( pCsr->ePlan ){
251545 fts5FreeCursorComponents(pCsr);
251546 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
251547 }
251548
@@ -251562,12 +252521,18 @@
251562 switch( idxStr[iIdxStr++] ){
251563 case 'r':
251564 pRank = apVal[i];
251565 break;
251566 case 'M': {
251567 const char *zText = (const char*)sqlite3_value_text(apVal[i]);
 
 
 
 
 
251568 if( zText==0 ) zText = "";
 
251569 iCol = 0;
251570 do{
251571 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
251572 iIdxStr++;
251573 }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
@@ -251575,21 +252540,27 @@
251575 if( zText[0]=='*' ){
251576 /* The user has issued a query of the form "MATCH '*...'". This
251577 ** indicates that the MATCH expression is not a full text query,
251578 ** but a request for an internal parameter. */
251579 rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
251580 goto filter_out;
251581 }else{
251582 char **pzErr = &pTab->p.base.zErrMsg;
251583 rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
251584 if( rc==SQLITE_OK ){
251585 rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
251586 pExpr = 0;
251587 }
251588 if( rc!=SQLITE_OK ) goto filter_out;
251589 }
251590
 
 
 
 
 
 
 
251591 break;
251592 }
251593 case 'L':
251594 case 'G': {
251595 int bGlob = (idxStr[iIdxStr-1]=='G');
@@ -251893,11 +252864,11 @@
251893 ){
251894 int rc = SQLITE_OK;
251895 int eType1 = sqlite3_value_type(apVal[1]);
251896 if( eType1==SQLITE_INTEGER ){
251897 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
251898 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
251899 }
251900 return rc;
251901 }
251902
251903 static void fts5StorageInsert(
@@ -252017,59 +252988,81 @@
252017 }
252018
252019 /* DELETE */
252020 else if( nArg==1 ){
252021 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
252022 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
252023 bUpdateOrDelete = 1;
252024 }
252025
252026 /* INSERT or UPDATE */
252027 else{
252028 int eType1 = sqlite3_value_numeric_type(apVal[1]);
252029
252030 if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
252031 rc = SQLITE_MISMATCH;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252032 }
252033
252034 else if( eType0!=SQLITE_INTEGER ){
252035 /* An INSERT statement. If the conflict-mode is REPLACE, first remove
252036 ** the current entry (if any). */
252037 if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
252038 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
252039 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
252040 bUpdateOrDelete = 1;
252041 }
252042 fts5StorageInsert(&rc, pTab, apVal, pRowid);
252043 }
252044
252045 /* UPDATE */
252046 else{
252047 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
252048 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
252049 if( eType1==SQLITE_INTEGER && iOld!=iNew ){
 
 
252050 if( eConflict==SQLITE_REPLACE ){
252051 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
252052 if( rc==SQLITE_OK ){
252053 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
252054 }
252055 fts5StorageInsert(&rc, pTab, apVal, pRowid);
252056 }else{
252057 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
 
 
 
252058 if( rc==SQLITE_OK ){
252059 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
252060 }
252061 if( rc==SQLITE_OK ){
252062 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
252063 }
252064 }
252065 }else{
252066 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
252067 fts5StorageInsert(&rc, pTab, apVal, pRowid);
252068 }
252069 bUpdateOrDelete = 1;
 
252070 }
 
252071 }
252072 }
252073
252074 if( rc==SQLITE_OK
252075 && bUpdateOrDelete
@@ -252082,10 +253075,11 @@
252082 if( rc==SQLITE_OK ){
252083 pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
252084 }
252085 }
252086
 
252087 pTab->p.pConfig->pzErrmsg = 0;
252088 return rc;
252089 }
252090
252091 /*
@@ -252103,13 +253097,15 @@
252103
252104 /*
252105 ** Implementation of xBegin() method.
252106 */
252107 static int fts5BeginMethod(sqlite3_vtab *pVtab){
252108 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
252109 fts5NewTransaction((Fts5FullTable*)pVtab);
252110 return SQLITE_OK;
 
 
252111 }
252112
252113 /*
252114 ** Implementation of xCommit() method. This is a no-op. The contents of
252115 ** the pending-terms hash-table have already been flushed into the database
@@ -252159,21 +253155,44 @@
252159 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252160 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
252161 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
252162 }
252163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252164 static int fts5ApiTokenize(
252165 Fts5Context *pCtx,
252166 const char *pText, int nText,
252167 void *pUserData,
252168 int (*xToken)(void*, int, const char*, int, int, int)
252169 ){
252170 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252171 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
252172 return sqlite3Fts5Tokenize(
252173 pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
252174 );
252175 }
252176
252177 static int fts5ApiPhraseCount(Fts5Context *pCtx){
252178 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252179 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
@@ -252191,53 +253210,76 @@
252191 int *pn
252192 ){
252193 int rc = SQLITE_OK;
252194 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
252195 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
 
 
252196 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
252197 rc = SQLITE_RANGE;
252198 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
252199 || pCsr->ePlan==FTS5_PLAN_SPECIAL
252200 ){
252201 *pz = 0;
252202 *pn = 0;
252203 }else{
252204 rc = fts5SeekCursor(pCsr, 0);
252205 if( rc==SQLITE_OK ){
252206 *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
252207 *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
 
 
252208 }
252209 }
252210 return rc;
252211 }
252212
 
 
 
 
 
 
 
252213 static int fts5CsrPoslist(
252214 Fts5Cursor *pCsr,
252215 int iPhrase,
252216 const u8 **pa,
252217 int *pn
252218 ){
252219 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
252220 int rc = SQLITE_OK;
252221 int bLive = (pCsr->pSorter==0);
252222
252223 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
252224 rc = SQLITE_RANGE;
 
 
 
 
 
 
252225 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
252226 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
252227 Fts5PoslistPopulator *aPopulator;
252228 int i;
 
252229 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
252230 if( aPopulator==0 ) rc = SQLITE_NOMEM;
 
 
 
252231 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
252232 int n; const char *z;
252233 rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
 
 
 
252234 if( rc==SQLITE_OK ){
252235 rc = sqlite3Fts5ExprPopulatePoslists(
252236 pConfig, pCsr->pExpr, aPopulator, i, z, n
252237 );
252238 }
 
252239 }
252240 sqlite3_free(aPopulator);
252241
252242 if( pCsr->pSorter ){
252243 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -252257,11 +253299,10 @@
252257 }
252258 }else{
252259 *pa = 0;
252260 *pn = 0;
252261 }
252262
252263
252264 return rc;
252265 }
252266
252267 /*
@@ -252327,11 +253368,12 @@
252327
252328 aInst = &pCsr->aInst[3 * (nInst-1)];
252329 aInst[0] = iBest;
252330 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
252331 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
252332 if( aInst[1]<0 || aInst[1]>=nCol ){
 
252333 rc = FTS5_CORRUPT;
252334 break;
252335 }
252336 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
252337 }
@@ -252414,20 +253456,25 @@
252414 pCsr->aColumnSize[i] = -1;
252415 }
252416 }
252417 }else{
252418 int i;
 
252419 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
252420 if( pConfig->abUnindexed[i]==0 ){
252421 const char *z; int n;
252422 void *p = (void*)(&pCsr->aColumnSize[i]);
 
 
 
252423 pCsr->aColumnSize[i] = 0;
252424 rc = fts5ApiColumnText(pCtx, i, &z, &n);
252425 if( rc==SQLITE_OK ){
252426 rc = sqlite3Fts5Tokenize(
252427 pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
252428 );
 
252429 }
252430 }
252431 }
252432 }
252433 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
@@ -252669,13 +253716,76 @@
252669
252670
252671 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
252672 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
252673 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252674
252675 static const Fts5ExtensionApi sFts5Api = {
252676 3, /* iVersion */
252677 fts5ApiUserData,
252678 fts5ApiColumnCount,
252679 fts5ApiRowCount,
252680 fts5ApiColumnTotalSize,
252681 fts5ApiTokenize,
@@ -252692,11 +253802,13 @@
252692 fts5ApiPhraseFirst,
252693 fts5ApiPhraseNext,
252694 fts5ApiPhraseFirstColumn,
252695 fts5ApiPhraseNextColumn,
252696 fts5ApiQueryToken,
252697 fts5ApiInstToken
 
 
252698 };
252699
252700 /*
252701 ** Implementation of API function xQueryPhrase().
252702 */
@@ -252743,10 +253855,11 @@
252743 sqlite3_context *context,
252744 int argc,
252745 sqlite3_value **argv
252746 ){
252747 assert( pCsr->pAux==0 );
 
252748 pCsr->pAux = pAux;
252749 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
252750 pCsr->pAux = 0;
252751 }
252752
@@ -252755,10 +253868,25 @@
252755 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
252756 if( pCsr->iCsrId==iCsrId ) break;
252757 }
252758 return pCsr;
252759 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252760
252761 static void fts5ApiCallback(
252762 sqlite3_context *context,
252763 int argc,
252764 sqlite3_value **argv
@@ -252771,14 +253899,12 @@
252771 assert( argc>=1 );
252772 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
252773 iCsrId = sqlite3_value_int64(argv[0]);
252774
252775 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
252776 if( pCsr==0 || pCsr->ePlan==0 ){
252777 char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
252778 sqlite3_result_error(context, zErr, -1);
252779 sqlite3_free(zErr);
252780 }else{
252781 sqlite3_vtab *pTab = pCsr->base.pVtab;
252782 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
252783 sqlite3_free(pTab->zErrMsg);
252784 pTab->zErrMsg = 0;
@@ -252867,10 +253993,61 @@
252867 }
252868
252869 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
252870 return rc;
252871 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252872
252873 /*
252874 ** This is the xColumn method, called by SQLite to request a value from
252875 ** the row that the supplied cursor currently points to.
252876 */
@@ -252897,12 +254074,12 @@
252897 ** as the table. Return the cursor integer id number. This value is only
252898 ** useful in that it may be passed as the first argument to an FTS5
252899 ** auxiliary function. */
252900 sqlite3_result_int64(pCtx, pCsr->iCsrId);
252901 }else if( iCol==pConfig->nCol+1 ){
252902
252903 /* The value of the "rank" column. */
 
252904 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
252905 fts5PoslistBlob(pCtx, pCsr);
252906 }else if(
252907 pCsr->ePlan==FTS5_PLAN_MATCH
252908 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
@@ -252909,24 +254086,31 @@
252909 ){
252910 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
252911 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
252912 }
252913 }
252914 }else if( !fts5IsContentless(pTab) ){
252915 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
252916 rc = fts5SeekCursor(pCsr, 1);
252917 if( rc==SQLITE_OK ){
252918 sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
252919 }
252920 pConfig->pzErrmsg = 0;
252921 }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
252922 char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
252923 "columns on fts5 contentless-delete table: %s", pConfig->zName
252924 );
252925 sqlite3_result_error(pCtx, zErr, -1);
252926 sqlite3_free(zErr);
252927 }
 
 
 
 
 
 
 
252928 return rc;
252929 }
252930
252931
252932 /*
@@ -253060,53 +254244,216 @@
253060 }
253061 }
253062
253063 return rc;
253064 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253065
253066 /*
253067 ** Register a new tokenizer. This is the implementation of the
253068 ** fts5_api.xCreateTokenizer() method.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253069 */
253070 static int fts5CreateTokenizer(
253071 fts5_api *pApi, /* Global context (one per db handle) */
253072 const char *zName, /* Name of new function */
253073 void *pUserData, /* User data for aux. function */
253074 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
253075 void(*xDestroy)(void*) /* Destructor for pUserData */
253076 ){
253077 Fts5Global *pGlobal = (Fts5Global*)pApi;
253078 Fts5TokenizerModule *pNew;
253079 sqlite3_int64 nName; /* Size of zName and its \0 terminator */
253080 sqlite3_int64 nByte; /* Bytes of space to allocate */
253081 int rc = SQLITE_OK;
253082
253083 nName = strlen(zName) + 1;
253084 nByte = sizeof(Fts5TokenizerModule) + nName;
253085 pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
253086 if( pNew ){
253087 memset(pNew, 0, (size_t)nByte);
253088 pNew->zName = (char*)&pNew[1];
253089 memcpy(pNew->zName, zName, nName);
253090 pNew->pUserData = pUserData;
253091 pNew->x = *pTokenizer;
253092 pNew->xDestroy = xDestroy;
253093 pNew->pNext = pGlobal->pTok;
253094 pGlobal->pTok = pNew;
253095 if( pNew->pNext==0 ){
253096 pGlobal->pDfltTok = pNew;
253097 }
253098 }else{
253099 rc = SQLITE_NOMEM;
253100 }
253101
253102 return rc;
253103 }
253104
 
 
 
 
 
253105 static Fts5TokenizerModule *fts5LocateTokenizer(
253106 Fts5Global *pGlobal,
253107 const char *zName
253108 ){
253109 Fts5TokenizerModule *pMod = 0;
253110
253111 if( zName==0 ){
253112 pMod = pGlobal->pDfltTok;
@@ -253116,10 +254463,40 @@
253116 }
253117 }
253118
253119 return pMod;
253120 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253121
253122 /*
253123 ** Find a tokenizer. This is the implementation of the
253124 ** fts5_api.xFindTokenizer() method.
253125 */
@@ -253132,70 +254509,79 @@
253132 int rc = SQLITE_OK;
253133 Fts5TokenizerModule *pMod;
253134
253135 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
253136 if( pMod ){
253137 *pTokenizer = pMod->x;
253138 *ppUserData = pMod->pUserData;
253139 }else{
253140 memset(pTokenizer, 0, sizeof(fts5_tokenizer));
253141 rc = SQLITE_ERROR;
253142 }
253143
253144 return rc;
253145 }
253146
253147 int fts5GetTokenizer(
253148 Fts5Global *pGlobal,
253149 const char **azArg,
253150 int nArg,
253151 Fts5Config *pConfig,
253152 char **pzErr
253153 ){
253154 Fts5TokenizerModule *pMod;
253155 int rc = SQLITE_OK;
253156
253157 pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
253158 if( pMod==0 ){
253159 assert( nArg>0 );
253160 rc = SQLITE_ERROR;
253161 if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
253162 }else{
253163 rc = pMod->x.xCreate(
253164 pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
253165 );
253166 pConfig->t.pTokApi = &pMod->x;
253167 if( rc!=SQLITE_OK ){
253168 if( pzErr && rc!=SQLITE_NOMEM ){
253169 *pzErr = sqlite3_mprintf("error in tokenizer constructor");
253170 }
253171 }else{
253172 pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
253173 pMod->x.xCreate, pConfig->t.pTok
253174 );
253175 }
253176 }
253177
253178 if( rc!=SQLITE_OK ){
253179 pConfig->t.pTokApi = 0;
253180 pConfig->t.pTok = 0;
253181 }
253182
253183 return rc;
253184 }
253185
253186 /*
253187 ** Attempt to instantiate the tokenizer.
253188 */
253189 static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
253190 return fts5GetTokenizer(
253191 pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg,
253192 pConfig, pConfig->pzErrmsg
253193 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253194 }
253195
253196
 
 
 
 
 
253197 static void fts5ModuleDestroy(void *pCtx){
253198 Fts5TokenizerModule *pTok, *pNextTok;
253199 Fts5Auxiliary *pAux, *pNextAux;
253200 Fts5Global *pGlobal = (Fts5Global*)pCtx;
253201
@@ -253212,10 +254598,14 @@
253212 }
253213
253214 sqlite3_free(pGlobal);
253215 }
253216
 
 
 
 
253217 static void fts5Fts5Func(
253218 sqlite3_context *pCtx, /* Function call context */
253219 int nArg, /* Number of args */
253220 sqlite3_value **apArg /* Function arguments */
253221 ){
@@ -253235,11 +254625,74 @@
253235 int nArg, /* Number of args */
253236 sqlite3_value **apUnused /* Function arguments */
253237 ){
253238 assert( nArg==0 );
253239 UNUSED_PARAM2(nArg, apUnused);
253240 sqlite3_result_text(pCtx, "fts5: 2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9", -1, SQLITE_TRANSIENT);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253241 }
253242
253243 /*
253244 ** Return true if zName is the extension on one of the shadow tables used
253245 ** by this module.
@@ -253330,14 +254783,16 @@
253330 rc = SQLITE_NOMEM;
253331 }else{
253332 void *p = (void*)pGlobal;
253333 memset(pGlobal, 0, sizeof(Fts5Global));
253334 pGlobal->db = db;
253335 pGlobal->api.iVersion = 2;
253336 pGlobal->api.xCreateFunction = fts5CreateAux;
253337 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
253338 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
 
 
253339 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
253340 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
253341 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
253342 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
253343 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -253351,10 +254806,17 @@
253351 rc = sqlite3_create_function(
253352 db, "fts5_source_id", 0,
253353 SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
253354 p, fts5SourceIdFunc, 0, 0
253355 );
 
 
 
 
 
 
 
253356 }
253357 }
253358
253359 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
253360 ** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -253426,17 +254888,44 @@
253426
253427
253428
253429 /* #include "fts5Int.h" */
253430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253431 struct Fts5Storage {
253432 Fts5Config *pConfig;
253433 Fts5Index *pIndex;
253434 int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
253435 i64 nTotalRow; /* Total number of rows in FTS table */
253436 i64 *aTotalSize; /* Total sizes of each column */
253437 sqlite3_stmt *aStmt[11];
 
253438 };
253439
253440
253441 #if FTS5_STMT_SCAN_ASC!=0
253442 # error "FTS5_STMT_SCAN_ASC mismatch"
@@ -253446,18 +254935,19 @@
253446 #endif
253447 #if FTS5_STMT_LOOKUP!=2
253448 # error "FTS5_STMT_LOOKUP mismatch"
253449 #endif
253450
253451 #define FTS5_STMT_INSERT_CONTENT 3
253452 #define FTS5_STMT_REPLACE_CONTENT 4
253453 #define FTS5_STMT_DELETE_CONTENT 5
253454 #define FTS5_STMT_REPLACE_DOCSIZE 6
253455 #define FTS5_STMT_DELETE_DOCSIZE 7
253456 #define FTS5_STMT_LOOKUP_DOCSIZE 8
253457 #define FTS5_STMT_REPLACE_CONFIG 9
253458 #define FTS5_STMT_SCAN 10
 
253459
253460 /*
253461 ** Prepare the two insert statements - Fts5Storage.pInsertContent and
253462 ** Fts5Storage.pInsertDocsize - if they have not already been prepared.
253463 ** Return SQLITE_OK if successful, or an SQLite error code if an error
@@ -253483,10 +254973,11 @@
253483 if( p->aStmt[eStmt]==0 ){
253484 const char *azStmt[] = {
253485 "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
253486 "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
253487 "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
 
253488
253489 "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
253490 "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
253491 "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
253492 "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
@@ -253497,10 +254988,12 @@
253497 "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
253498 "SELECT %s FROM %s AS T", /* SCAN */
253499 };
253500 Fts5Config *pC = p->pConfig;
253501 char *zSql = 0;
 
 
253502
253503 switch( eStmt ){
253504 case FTS5_STMT_SCAN:
253505 zSql = sqlite3_mprintf(azStmt[eStmt],
253506 pC->zContentExprlist, pC->zContent
@@ -253514,10 +255007,11 @@
253514 pC->zContentRowid
253515 );
253516 break;
253517
253518 case FTS5_STMT_LOOKUP:
 
253519 zSql = sqlite3_mprintf(azStmt[eStmt],
253520 pC->zContentExprlist, pC->zContent, pC->zContentRowid
253521 );
253522 break;
253523
@@ -253560,11 +255054,11 @@
253560
253561 if( zSql==0 ){
253562 rc = SQLITE_NOMEM;
253563 }else{
253564 int f = SQLITE_PREPARE_PERSISTENT;
253565 if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
253566 p->pConfig->bLock++;
253567 rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
253568 p->pConfig->bLock--;
253569 sqlite3_free(zSql);
253570 if( rc!=SQLITE_OK && pzErrMsg ){
@@ -253808,74 +255302,141 @@
253808 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
253809 pCtx->szCol++;
253810 }
253811 return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
253812 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253813
253814 /*
253815 ** If a row with rowid iDel is present in the %_content table, add the
253816 ** delete-markers to the FTS index necessary to delete it. Do not actually
253817 ** remove the %_content row at this time though.
 
 
 
 
 
253818 */
253819 static int fts5StorageDeleteFromIndex(
253820 Fts5Storage *p,
253821 i64 iDel,
253822 sqlite3_value **apVal
 
253823 ){
253824 Fts5Config *pConfig = p->pConfig;
253825 sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
253826 int rc = SQLITE_OK; /* Return code */
253827 int rc2; /* sqlite3_reset() return code */
253828 int iCol;
253829 Fts5InsertCtx ctx;
253830
 
 
 
 
253831 if( apVal==0 ){
253832 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
253833 if( rc!=SQLITE_OK ) return rc;
253834 sqlite3_bind_int64(pSeek, 1, iDel);
253835 if( sqlite3_step(pSeek)!=SQLITE_ROW ){
253836 return sqlite3_reset(pSeek);
 
 
 
 
 
253837 }
253838 }
253839
253840 ctx.pStorage = p;
253841 ctx.iCol = -1;
253842 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
253843 if( pConfig->abUnindexed[iCol-1]==0 ){
253844 const char *zText;
253845 int nText;
 
 
 
253846 assert( pSeek==0 || apVal==0 );
253847 assert( pSeek!=0 || apVal!=0 );
253848 if( pSeek ){
253849 zText = (const char*)sqlite3_column_text(pSeek, iCol);
253850 nText = sqlite3_column_bytes(pSeek, iCol);
253851 }else if( ALWAYS(apVal) ){
253852 zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
253853 nText = sqlite3_value_bytes(apVal[iCol-1]);
253854 }else{
253855 continue;
253856 }
253857 ctx.szCol = 0;
253858 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
253859 zText, nText, (void*)&ctx, fts5StorageInsertCallback
253860 );
253861 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
253862 if( p->aTotalSize[iCol-1]<0 && rc==SQLITE_OK ){
253863 rc = FTS5_CORRUPT;
 
 
 
 
 
 
 
253864 }
253865 }
253866 }
253867 if( rc==SQLITE_OK && p->nTotalRow<1 ){
253868 rc = FTS5_CORRUPT;
253869 }else{
253870 p->nTotalRow--;
253871 }
253872
253873 rc2 = sqlite3_reset(pSeek);
253874 if( rc==SQLITE_OK ) rc = rc2;
 
 
 
 
 
253875 return rc;
253876 }
 
 
 
 
 
 
 
 
 
 
 
 
 
253877
253878 /*
253879 ** This function is called to process a DELETE on a contentless_delete=1
253880 ** table. It adds the tombstone required to delete the entry with rowid
253881 ** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
@@ -253929,16 +255490,16 @@
253929 if( p->pConfig->bContentlessDelete ){
253930 i64 iOrigin = 0;
253931 rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
253932 sqlite3_bind_int64(pReplace, 3, iOrigin);
253933 }
253934 if( rc==SQLITE_OK ){
253935 sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
253936 sqlite3_step(pReplace);
253937 rc = sqlite3_reset(pReplace);
253938 sqlite3_bind_null(pReplace, 2);
253939 }
253940 }
253941 }
253942 return rc;
253943 }
253944
@@ -253988,11 +255549,16 @@
253988 }
253989
253990 /*
253991 ** Remove a row from the FTS table.
253992 */
253993 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
 
 
 
 
 
253994 Fts5Config *pConfig = p->pConfig;
253995 int rc;
253996 sqlite3_stmt *pDel = 0;
253997
253998 assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
@@ -254005,11 +255571,11 @@
254005
254006 if( rc==SQLITE_OK ){
254007 if( p->pConfig->bContentlessDelete ){
254008 rc = fts5StorageContentlessDelete(p, iDel);
254009 }else{
254010 rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
254011 }
254012 }
254013
254014 /* Delete the %_docsize record */
254015 if( rc==SQLITE_OK && pConfig->bColumnsize ){
@@ -254094,18 +255660,25 @@
254094 sqlite3Fts5BufferZero(&buf);
254095 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
254096 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
254097 ctx.szCol = 0;
254098 if( pConfig->abUnindexed[ctx.iCol]==0 ){
254099 const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
254100 int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
254101 rc = sqlite3Fts5Tokenize(pConfig,
254102 FTS5_TOKENIZE_DOCUMENT,
254103 zText, nText,
254104 (void*)&ctx,
254105 fts5StorageInsertCallback
254106 );
 
 
 
 
 
 
 
254107 }
254108 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
254109 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
254110 }
254111 p->nTotalRow++;
@@ -254185,11 +255758,35 @@
254185 }else{
254186 sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
254187 int i; /* Counter variable */
254188 rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
254189 for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
254190 rc = sqlite3_bind_value(pInsert, i, apVal[i]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254191 }
254192 if( rc==SQLITE_OK ){
254193 sqlite3_step(pInsert);
254194 rc = sqlite3_reset(pInsert);
254195 }
@@ -254220,18 +255817,28 @@
254220 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
254221 }
254222 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
254223 ctx.szCol = 0;
254224 if( pConfig->abUnindexed[ctx.iCol]==0 ){
254225 const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
254226 int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
254227 rc = sqlite3Fts5Tokenize(pConfig,
254228 FTS5_TOKENIZE_DOCUMENT,
254229 zText, nText,
254230 (void*)&ctx,
254231 fts5StorageInsertCallback
254232 );
 
 
 
 
 
 
 
 
 
 
254233 }
254234 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
254235 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
254236 }
254237 p->nTotalRow++;
@@ -254398,18 +256005,26 @@
254398 ctx.szCol = 0;
254399 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
254400 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
254401 }
254402 if( rc==SQLITE_OK ){
254403 const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
254404 int nText = sqlite3_column_bytes(pScan, i+1);
254405 rc = sqlite3Fts5Tokenize(pConfig,
254406 FTS5_TOKENIZE_DOCUMENT,
254407 zText, nText,
254408 (void*)&ctx,
254409 fts5StorageIntegrityCallback
254410 );
 
 
 
 
 
 
 
 
 
254411 }
254412 if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
254413 rc = FTS5_CORRUPT;
254414 }
254415 aTotalSize[i] += ctx.szCol;
@@ -254720,11 +256335,11 @@
254720 rc = SQLITE_NOMEM;
254721 }else{
254722 int i;
254723 memset(p, 0, sizeof(AsciiTokenizer));
254724 memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
254725 for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
254726 const char *zArg = azArg[i+1];
254727 if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
254728 fts5AsciiAddExceptions(p, zArg, 1);
254729 }else
254730 if( 0==sqlite3_stricmp(azArg[i], "separators") ){
@@ -254731,11 +256346,10 @@
254731 fts5AsciiAddExceptions(p, zArg, 0);
254732 }else{
254733 rc = SQLITE_ERROR;
254734 }
254735 }
254736 if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
254737 if( rc!=SQLITE_OK ){
254738 fts5AsciiDelete((Fts5Tokenizer*)p);
254739 p = 0;
254740 }
254741 }
@@ -255023,20 +256637,20 @@
255023 if( p->aFold==0 ){
255024 rc = SQLITE_NOMEM;
255025 }
255026
255027 /* Search for a "categories" argument */
255028 for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
255029 if( 0==sqlite3_stricmp(azArg[i], "categories") ){
255030 zCat = azArg[i+1];
255031 }
255032 }
255033 if( rc==SQLITE_OK ){
255034 rc = unicodeSetCategories(p, zCat);
255035 }
255036
255037 for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
255038 const char *zArg = azArg[i+1];
255039 if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
255040 if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
255041 rc = SQLITE_ERROR;
255042 }else{
@@ -255057,12 +256671,10 @@
255057 /* no-op */
255058 }else{
255059 rc = SQLITE_ERROR;
255060 }
255061 }
255062 if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
255063
255064 }else{
255065 rc = SQLITE_NOMEM;
255066 }
255067 if( rc!=SQLITE_OK ){
255068 fts5UnicodeDelete((Fts5Tokenizer*)p);
@@ -255197,11 +256809,11 @@
255197 ** stemming. */
255198 #define FTS5_PORTER_MAX_TOKEN 64
255199
255200 typedef struct PorterTokenizer PorterTokenizer;
255201 struct PorterTokenizer {
255202 fts5_tokenizer tokenizer; /* Parent tokenizer module */
255203 Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
255204 char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
255205 };
255206
255207 /*
@@ -255209,11 +256821,11 @@
255209 */
255210 static void fts5PorterDelete(Fts5Tokenizer *pTok){
255211 if( pTok ){
255212 PorterTokenizer *p = (PorterTokenizer*)pTok;
255213 if( p->pTokenizer ){
255214 p->tokenizer.xDelete(p->pTokenizer);
255215 }
255216 sqlite3_free(p);
255217 }
255218 }
255219
@@ -255228,26 +256840,28 @@
255228 fts5_api *pApi = (fts5_api*)pCtx;
255229 int rc = SQLITE_OK;
255230 PorterTokenizer *pRet;
255231 void *pUserdata = 0;
255232 const char *zBase = "unicode61";
 
255233
255234 if( nArg>0 ){
255235 zBase = azArg[0];
255236 }
255237
255238 pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
255239 if( pRet ){
255240 memset(pRet, 0, sizeof(PorterTokenizer));
255241 rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
255242 }else{
255243 rc = SQLITE_NOMEM;
255244 }
255245 if( rc==SQLITE_OK ){
255246 int nArg2 = (nArg>0 ? nArg-1 : 0);
255247 const char **azArg2 = (nArg2 ? &azArg[1] : 0);
255248 rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
 
255249 }
255250
255251 if( rc!=SQLITE_OK ){
255252 fts5PorterDelete((Fts5Tokenizer*)pRet);
255253 pRet = 0;
@@ -255894,19 +257508,20 @@
255894 static int fts5PorterTokenize(
255895 Fts5Tokenizer *pTokenizer,
255896 void *pCtx,
255897 int flags,
255898 const char *pText, int nText,
 
255899 int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
255900 ){
255901 PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
255902 PorterContext sCtx;
255903 sCtx.xToken = xToken;
255904 sCtx.pCtx = pCtx;
255905 sCtx.aBuf = p->aBuf;
255906 return p->tokenizer.xTokenize(
255907 p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
255908 );
255909 }
255910
255911 /**************************************************************************
255912 ** Start of trigram implementation.
@@ -255932,45 +257547,50 @@
255932 const char **azArg,
255933 int nArg,
255934 Fts5Tokenizer **ppOut
255935 ){
255936 int rc = SQLITE_OK;
255937 TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
255938 UNUSED_PARAM(pUnused);
255939 if( pNew==0 ){
255940 rc = SQLITE_NOMEM;
255941 }else{
255942 int i;
255943 pNew->bFold = 1;
255944 pNew->iFoldParam = 0;
255945 for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
255946 const char *zArg = azArg[i+1];
255947 if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
255948 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
255949 rc = SQLITE_ERROR;
255950 }else{
255951 pNew->bFold = (zArg[0]=='0');
255952 }
255953 }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
255954 if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
255955 rc = SQLITE_ERROR;
255956 }else{
255957 pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
255958 }
255959 }else{
255960 rc = SQLITE_ERROR;
255961 }
255962 }
255963 if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
255964
255965 if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
255966 rc = SQLITE_ERROR;
255967 }
255968
255969 if( rc!=SQLITE_OK ){
255970 fts5TriDelete((Fts5Tokenizer*)pNew);
255971 pNew = 0;
 
 
 
 
 
255972 }
255973 }
255974 *ppOut = (Fts5Tokenizer*)pNew;
255975 return rc;
255976 }
@@ -256091,11 +257711,10 @@
256091 const char *zName;
256092 fts5_tokenizer x;
256093 } aBuiltin[] = {
256094 { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
256095 { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
256096 { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
256097 { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
256098 };
256099
256100 int rc = SQLITE_OK; /* Return code */
256101 int i; /* To iterate through builtin functions */
@@ -256106,11 +257725,24 @@
256106 (void*)pApi,
256107 &aBuiltin[i].x,
256108 0
256109 );
256110 }
256111
 
 
 
 
 
 
 
 
 
 
 
 
 
256112 return rc;
256113 }
256114
256115 /*
256116 ** 2012-05-25
@@ -256476,10 +258108,13 @@
256476 aArray[29] = 1;
256477 break;
256478 default: return 1; }
256479 break;
256480
 
 
 
256481 }
256482 return 0;
256483 }
256484
256485 static u16 aFts5UnicodeBlock[] = {
256486
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -16,11 +16,11 @@
16 ** if you want a wrapper to interface SQLite with your choice of programming
17 ** language. The code for the "sqlite3" command-line shell is also in a
18 ** separate file. This file contains only code for the core SQLite library.
19 **
20 ** The content in this amalgamation comes from Fossil check-in
21 ** 7891a266c4425722ae8b9231397ef9e42e24.
22 */
23 #define SQLITE_CORE 1
24 #define SQLITE_AMALGAMATION 1
25 #ifndef SQLITE_PRIVATE
26 # define SQLITE_PRIVATE static
@@ -462,11 +462,11 @@
462 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
463 ** [sqlite_version()] and [sqlite_source_id()].
464 */
465 #define SQLITE_VERSION "3.47.0"
466 #define SQLITE_VERSION_NUMBER 3047000
467 #define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
468
469 /*
470 ** CAPI3REF: Run-Time Library Version Numbers
471 ** KEYWORDS: sqlite3_version sqlite3_sourceid
472 **
@@ -5929,18 +5929,28 @@
5929 ** might become a no-op if the function is used as term in an
5930 ** [expression index]. On the other hand, SQL functions that never invoke
5931 ** [sqlite3_result_subtype()] should avoid setting this property, as the
5932 ** purpose of this property is to disable certain optimizations that are
5933 ** incompatible with subtypes.
5934 **
5935 ** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
5936 ** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
5937 ** that internally orders the values provided to the first argument. The
5938 ** ordered-set aggregate SQL notation with a single ORDER BY term can be
5939 ** used to invoke this function. If the ordered-set aggregate notation is
5940 ** used on a function that lacks this flag, then an error is raised. Note
5941 ** that the ordered-set aggregate syntax is only available if SQLite is
5942 ** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
5943 ** </dd>
5944 ** </dl>
5945 */
5946 #define SQLITE_DETERMINISTIC 0x000000800
5947 #define SQLITE_DIRECTONLY 0x000080000
5948 #define SQLITE_SUBTYPE 0x000100000
5949 #define SQLITE_INNOCUOUS 0x000200000
5950 #define SQLITE_RESULT_SUBTYPE 0x001000000
5951 #define SQLITE_SELFORDER1 0x002000000
5952
5953 /*
5954 ** CAPI3REF: Deprecated Functions
5955 ** DEPRECATED
5956 **
@@ -7741,13 +7751,15 @@
7751 **
7752 ** ^The estimatedRows value is an estimate of the number of rows that
7753 ** will be returned by the strategy.
7754 **
7755 ** The xBestIndex method may optionally populate the idxFlags field with a
7756 ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
7757 ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
7758 ** output to show the idxNum has hex instead of as decimal. Another flag is
7759 ** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
7760 ** return at most one row.
7761 **
7762 ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
7763 ** SQLite also assumes that if a call to the xUpdate() method is made as
7764 ** part of the same statement to delete or update a virtual table row and the
7765 ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7807,11 +7819,13 @@
7819 **
7820 ** Virtual table implementations are allowed to set the
7821 ** [sqlite3_index_info].idxFlags field to some combination of
7822 ** these bits.
7823 */
7824 #define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
7825 #define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
7826 /* in EXPLAIN QUERY PLAN */
7827
7828 /*
7829 ** CAPI3REF: Virtual Table Constraint Operator Codes
7830 **
7831 ** These macros define the allowed values for the
@@ -8644,10 +8658,11 @@
8658 #define SQLITE_TESTCTRL_ALWAYS 13
8659 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
8660 #define SQLITE_TESTCTRL_JSON_SELFCHECK 14
8661 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15
8662 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
8663 #define SQLITE_TESTCTRL_GETOPT 16
8664 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
8665 #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
8666 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
8667 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
8668 #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13418,13 +13433,36 @@
13433 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13434 ** includes any embedded 0x00 and trailing data.
13435 **
13436 ** This API can be quite slow if used with an FTS5 table created with the
13437 ** "detail=none" or "detail=column" option.
13438 **
13439 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
13440 ** If parameter iCol is less than zero, or greater than or equal to the
13441 ** number of columns in the table, SQLITE_RANGE is returned.
13442 **
13443 ** Otherwise, this function attempts to retrieve the locale associated
13444 ** with column iCol of the current row. Usually, there is no associated
13445 ** locale, and output parameters (*pzLocale) and (*pnLocale) are set
13446 ** to NULL and 0, respectively. However, if the fts5_locale() function
13447 ** was used to associate a locale with the value when it was inserted
13448 ** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
13449 ** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
13450 ** is set to the size in bytes of the buffer, not including the
13451 ** nul-terminator.
13452 **
13453 ** If successful, SQLITE_OK is returned. Or, if an error occurs, an
13454 ** SQLite error code is returned. The final value of the output parameters
13455 ** is undefined in this case.
13456 **
13457 ** xTokenize_v2:
13458 ** Tokenize text using the tokenizer belonging to the FTS5 table. This
13459 ** API is the same as the xTokenize() API, except that it allows a tokenizer
13460 ** locale to be specified.
13461 */
13462 struct Fts5ExtensionApi {
13463 int iVersion; /* Currently always set to 4 */
13464
13465 void *(*xUserData)(Fts5Context*);
13466
13467 int (*xColumnCount)(Fts5Context*);
13468 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13462,10 +13500,19 @@
13500 int (*xQueryToken)(Fts5Context*,
13501 int iPhrase, int iToken,
13502 const char **ppToken, int *pnToken
13503 );
13504 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
13505
13506 /* Below this point are iVersion>=4 only */
13507 int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
13508 int (*xTokenize_v2)(Fts5Context*,
13509 const char *pText, int nText, /* Text to tokenize */
13510 const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
13511 void *pCtx, /* Context passed to xToken() */
13512 int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
13513 );
13514 };
13515
13516 /*
13517 ** CUSTOM AUXILIARY FUNCTIONS
13518 *************************************************************************/
@@ -13474,19 +13521,20 @@
13521 ** CUSTOM TOKENIZERS
13522 **
13523 ** Applications may also register custom tokenizer types. A tokenizer
13524 ** is registered by providing fts5 with a populated instance of the
13525 ** following structure. All structure methods must be defined, setting
13526 **
13527 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13528 ** behaviour. The structure methods are expected to function as follows:
13529 **
13530 ** xCreate:
13531 ** This function is used to allocate and initialize a tokenizer instance.
13532 ** A tokenizer instance is required to actually tokenize text.
13533 **
13534 ** The first argument passed to this function is a copy of the (void*)
13535 ** pointer provided by the application when the fts5_tokenizer_v2 object
13536 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
13537 ** The second and third arguments are an array of nul-terminated strings
13538 ** containing the tokenizer arguments, if any, specified following the
13539 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
13540 ** to create the FTS5 table.
@@ -13506,11 +13554,11 @@
13554 ** This function is expected to tokenize the nText byte string indicated
13555 ** by argument pText. pText may or may not be nul-terminated. The first
13556 ** argument passed to this function is a pointer to an Fts5Tokenizer object
13557 ** returned by an earlier call to xCreate().
13558 **
13559 ** The third argument indicates the reason that FTS5 is requesting
13560 ** tokenization of the supplied text. This is always one of the following
13561 ** four values:
13562 **
13563 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
13564 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -13529,10 +13577,17 @@
13577 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
13578 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
13579 ** function. Or an fts5_api.xColumnSize() request made by the same
13580 ** on a columnsize=0 database.
13581 ** </ul>
13582 **
13583 ** The sixth and seventh arguments passed to xTokenize() - pLocale and
13584 ** nLocale - are a pointer to a buffer containing the locale to use for
13585 ** tokenization (e.g. "en_US") and its size in bytes, respectively. The
13586 ** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
13587 ** which case nLocale is always 0) to indicate that the tokenizer should
13588 ** use its default locale.
13589 **
13590 ** For each token in the input string, the supplied callback xToken() must
13591 ** be invoked. The first argument to it should be a copy of the pointer
13592 ** passed as the second argument to xTokenize(). The third and fourth
13593 ** arguments are a pointer to a buffer containing the token text, and the
@@ -13552,10 +13607,34 @@
13607 ** immediately return a copy of the xToken() return value. Or, if the
13608 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
13609 ** if an error occurs with the xTokenize() implementation itself, it
13610 ** may abandon the tokenization and return any error code other than
13611 ** SQLITE_OK or SQLITE_DONE.
13612 **
13613 ** If the tokenizer is registered using an fts5_tokenizer_v2 object,
13614 ** then the xTokenize() method has two additional arguments - pLocale
13615 ** and nLocale. These specify the locale that the tokenizer should use
13616 ** for the current request. If pLocale and nLocale are both 0, then the
13617 ** tokenizer should use its default locale. Otherwise, pLocale points to
13618 ** an nLocale byte buffer containing the name of the locale to use as utf-8
13619 ** text. pLocale is not nul-terminated.
13620 **
13621 ** FTS5_TOKENIZER
13622 **
13623 ** There is also an fts5_tokenizer object. This is an older, deprecated,
13624 ** version of fts5_tokenizer_v2. It is similar except that:
13625 **
13626 ** <ul>
13627 ** <li> There is no "iVersion" field, and
13628 ** <li> The xTokenize() method does not take a locale argument.
13629 ** </ul>
13630 **
13631 ** Legacy fts5_tokenizer tokenizers must be registered using the
13632 ** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
13633 **
13634 ** Tokenizer implementations registered using either API may be retrieved
13635 ** using both xFindTokenizer() and xFindTokenizer_v2().
13636 **
13637 ** SYNONYM SUPPORT
13638 **
13639 ** Custom tokenizers may also support synonyms. Consider a case in which a
13640 ** user wishes to query for a phrase such as "first place". Using the
@@ -13661,10 +13740,37 @@
13740 ** provide synonyms when tokenizing document text (method (3)) or query
13741 ** text (method (2)), not both. Doing so will not cause any errors, but is
13742 ** inefficient.
13743 */
13744 typedef struct Fts5Tokenizer Fts5Tokenizer;
13745 typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
13746 struct fts5_tokenizer_v2 {
13747 int iVersion; /* Currently always 2 */
13748
13749 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13750 void (*xDelete)(Fts5Tokenizer*);
13751 int (*xTokenize)(Fts5Tokenizer*,
13752 void *pCtx,
13753 int flags, /* Mask of FTS5_TOKENIZE_* flags */
13754 const char *pText, int nText,
13755 const char *pLocale, int nLocale,
13756 int (*xToken)(
13757 void *pCtx, /* Copy of 2nd argument to xTokenize() */
13758 int tflags, /* Mask of FTS5_TOKEN_* flags */
13759 const char *pToken, /* Pointer to buffer containing token */
13760 int nToken, /* Size of token in bytes */
13761 int iStart, /* Byte offset of token within input text */
13762 int iEnd /* Byte offset of end of token within input text */
13763 )
13764 );
13765 };
13766
13767 /*
13768 ** New code should use the fts5_tokenizer_v2 type to define tokenizer
13769 ** implementations. The following type is included for legacy applications
13770 ** that still use it.
13771 */
13772 typedef struct fts5_tokenizer fts5_tokenizer;
13773 struct fts5_tokenizer {
13774 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13775 void (*xDelete)(Fts5Tokenizer*);
13776 int (*xTokenize)(Fts5Tokenizer*,
@@ -13679,10 +13785,11 @@
13785 int iStart, /* Byte offset of token within input text */
13786 int iEnd /* Byte offset of end of token within input text */
13787 )
13788 );
13789 };
13790
13791
13792 /* Flags that may be passed as the third argument to xTokenize() */
13793 #define FTS5_TOKENIZE_QUERY 0x0001
13794 #define FTS5_TOKENIZE_PREFIX 0x0002
13795 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13699,11 +13806,11 @@
13806 /*************************************************************************
13807 ** FTS5 EXTENSION REGISTRATION API
13808 */
13809 typedef struct fts5_api fts5_api;
13810 struct fts5_api {
13811 int iVersion; /* Currently always set to 3 */
13812
13813 /* Create a new tokenizer */
13814 int (*xCreateTokenizer)(
13815 fts5_api *pApi,
13816 const char *zName,
@@ -13726,10 +13833,29 @@
13833 const char *zName,
13834 void *pUserData,
13835 fts5_extension_function xFunction,
13836 void (*xDestroy)(void*)
13837 );
13838
13839 /* APIs below this point are only available if iVersion>=3 */
13840
13841 /* Create a new tokenizer */
13842 int (*xCreateTokenizer_v2)(
13843 fts5_api *pApi,
13844 const char *zName,
13845 void *pUserData,
13846 fts5_tokenizer_v2 *pTokenizer,
13847 void (*xDestroy)(void*)
13848 );
13849
13850 /* Find an existing tokenizer */
13851 int (*xFindTokenizer_v2)(
13852 fts5_api *pApi,
13853 const char *zName,
13854 void **ppUserData,
13855 fts5_tokenizer_v2 **ppTokenizer
13856 );
13857 };
13858
13859 /*
13860 ** END OF REGISTRATION API
13861 *************************************************************************/
@@ -14703,10 +14829,12 @@
14829 ** substitute integer for floating-point
14830 */
14831 #ifdef SQLITE_OMIT_FLOATING_POINT
14832 # define double sqlite_int64
14833 # define float sqlite_int64
14834 # define fabs(X) ((X)<0?-(X):(X))
14835 # define sqlite3IsOverflow(X) 0
14836 # define LONGDOUBLE_TYPE sqlite_int64
14837 # ifndef SQLITE_BIG_DBL
14838 # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
14839 # endif
14840 # define SQLITE_OMIT_DATETIME_FUNCS 1
@@ -15380,10 +15508,11 @@
15508 typedef struct RowSet RowSet;
15509 typedef struct Savepoint Savepoint;
15510 typedef struct Select Select;
15511 typedef struct SQLiteThread SQLiteThread;
15512 typedef struct SelectDest SelectDest;
15513 typedef struct Subquery Subquery;
15514 typedef struct SrcItem SrcItem;
15515 typedef struct SrcList SrcList;
15516 typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
15517 typedef struct Table Table;
15518 typedef struct TableLock TableLock;
@@ -19263,10 +19392,20 @@
19392 */
19393 #define EU4_NONE 0 /* Does not use IdList.a.u4 */
19394 #define EU4_IDX 1 /* Uses IdList.a.u4.idx */
19395 #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
19396
19397 /*
19398 ** Details of the implementation of a subquery.
19399 */
19400 struct Subquery {
19401 Select *pSelect; /* A SELECT statement used in place of a table name */
19402 int addrFillSub; /* Address of subroutine to initialize a subquery */
19403 int regReturn; /* Register holding return address of addrFillSub */
19404 int regResult; /* Registers holding results of a co-routine */
19405 };
19406
19407 /*
19408 ** The SrcItem object represents a single term in the FROM clause of a query.
19409 ** The SrcList object is mostly an array of SrcItems.
19410 **
19411 ** The jointype starts out showing the join type between the current table
@@ -19275,33 +19414,44 @@
19414 ** jointype expresses the join between the table and the previous table.
19415 **
19416 ** In the colUsed field, the high-order bit (bit 63) is set if the table
19417 ** contains more than 63 columns and the 64-th or later column is used.
19418 **
19419 ** Aggressive use of "union" helps keep the size of the object small. This
19420 ** has been shown to boost performance, in addition to saving memory.
19421 ** Access to union elements is gated by the following rules which should
19422 ** always be checked, either by an if-statement or by an assert().
19423 **
19424 ** Field Only access if this is true
19425 ** --------------- -----------------------------------
19426 ** u1.zIndexedBy fg.isIndexedBy
19427 ** u1.pFuncArg fg.isTabFunc
19428 ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy
19429 **
19430 ** u2.pIBIndex fg.isIndexedBy
19431 ** u2.pCteUse fg.isCte
19432 **
19433 ** u3.pOn !fg.isUsing
19434 ** u3.pUsing fg.isUsing
19435 **
19436 ** u4.zDatabase !fg.fixedSchema && !fg.isSubquery
19437 ** u4.pSchema fg.fixedSchema
19438 ** u4.pSubq fg.isSubquery
19439 **
19440 ** See also the sqlite3SrcListDelete() routine for assert() statements that
19441 ** check invariants on the fields of this object, especially the flags
19442 ** inside the fg struct.
19443 */
19444 struct SrcItem {
 
 
19445 char *zName; /* Name of the table */
19446 char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
19447 Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */
 
 
 
 
19448 struct {
19449 u8 jointype; /* Type of join between this table and the previous */
19450 unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
19451 unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
19452 unsigned isSubquery :1; /* True if this term is a subquery */
19453 unsigned isTabFunc :1; /* True if table-valued-function syntax */
19454 unsigned isCorrelated :1; /* True if sub-query is correlated */
19455 unsigned isMaterialized:1; /* This is a materialized view */
19456 unsigned viaCoroutine :1; /* Implemented as a co-routine */
19457 unsigned isRecursive :1; /* True for recursive reference in WITH */
@@ -19311,16 +19461,14 @@
19461 unsigned isUsing :1; /* u3.pUsing is valid */
19462 unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
19463 unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
19464 unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
19465 unsigned rowidUsed :1; /* The ROWID of this table is referenced */
19466 unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */
19467 unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */
19468 } fg;
19469 int iCursor; /* The VDBE cursor number used to access this table */
 
 
 
 
19470 Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
19471 union {
19472 char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
19473 ExprList *pFuncArg; /* Arguments to table-valued-function */
19474 u32 nRow; /* Number of rows in a VALUES clause */
@@ -19327,10 +19475,19 @@
19475 } u1;
19476 union {
19477 Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
19478 CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
19479 } u2;
19480 union {
19481 Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
19482 IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
19483 } u3;
19484 union {
19485 Schema *pSchema; /* Schema to which this item is fixed */
19486 char *zDatabase; /* Name of database holding this table */
19487 Subquery *pSubq; /* Description of a subquery */
19488 } u4;
19489 };
19490
19491 /*
19492 ** The OnOrUsing object represents either an ON clause or a USING clause.
19493 ** It can never be both at the same time, but it can be neither.
@@ -19586,12 +19743,14 @@
19743 #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
19744 #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
19745 #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
19746 #define SF_Correlated 0x20000000 /* True if references the outer context */
19747
19748 /* True if SrcItem X is a subquery that has SF_NestedFrom */
19749 #define IsNestedFrom(X) \
19750 ((X)->fg.isSubquery && \
19751 ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0)
19752
19753 /*
19754 ** The results of a SELECT can be distributed in several ways, as defined
19755 ** by one of the following macros. The "SRT" prefix means "SELECT Result
19756 ** Type".
@@ -20979,10 +21138,13 @@
21138 SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
21139 SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
21140 SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
21141 SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
21142 SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
21143 SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3*,Subquery*);
21144 SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*);
21145 SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int);
21146 SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
21147 Token*, Select*, OnOrUsing*);
21148 SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
21149 SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
21150 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *);
@@ -22204,10 +22366,13 @@
22366 #ifdef SQLITE_ENABLE_NULL_TRIM
22367 "ENABLE_NULL_TRIM",
22368 #endif
22369 #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
22370 "ENABLE_OFFSET_SQL_FUNC",
22371 #endif
22372 #ifdef SQLITE_ENABLE_ORDERED_SET_AGGREGATES
22373 "ENABLE_ORDERED_SET_AGGREGATES",
22374 #endif
22375 #ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
22376 "ENABLE_OVERSIZE_CELL_CHECK",
22377 #endif
22378 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
@@ -24521,12 +24686,12 @@
24686 }
24687 if( M<=2 ){
24688 Y--;
24689 M += 12;
24690 }
24691 A = (Y+4800)/100;
24692 B = 38 - A + (A/4);
24693 X1 = 36525*(Y+4716)/100;
24694 X2 = 306001*(M+1)/10000;
24695 p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
24696 p->validJD = 1;
24697 if( p->validHMS ){
@@ -24706,11 +24871,11 @@
24871
24872 /*
24873 ** Compute the Year, Month, and Day from the julian day number.
24874 */
24875 static void computeYMD(DateTime *p){
24876 int Z, alpha, A, B, C, D, E, X1;
24877 if( p->validYMD ) return;
24878 if( !p->validJD ){
24879 p->Y = 2000;
24880 p->M = 1;
24881 p->D = 1;
@@ -24717,12 +24882,12 @@
24882 }else if( !validJulianDay(p->iJD) ){
24883 datetimeError(p);
24884 return;
24885 }else{
24886 Z = (int)((p->iJD + 43200000)/86400000);
24887 alpha = (int)((Z + 32044.75)/36524.25) - 52;
24888 A = Z + 1 + alpha - ((alpha+100)/4) + 25;
24889 B = A + 1524;
24890 C = (int)((B - 122.1)/365.25);
24891 D = (36525*(C&32767))/100;
24892 E = (int)((B-D)/30.6001);
24893 X1 = (int)(30.6001*E);
@@ -32017,20 +32182,23 @@
32182 pItem = va_arg(ap, SrcItem*);
32183 assert( bArgList==0 );
32184 if( pItem->zAlias && !flag_altform2 ){
32185 sqlite3_str_appendall(pAccum, pItem->zAlias);
32186 }else if( pItem->zName ){
32187 if( pItem->fg.fixedSchema==0
32188 && pItem->fg.isSubquery==0
32189 && pItem->u4.zDatabase!=0
32190 ){
32191 sqlite3_str_appendall(pAccum, pItem->u4.zDatabase);
32192 sqlite3_str_append(pAccum, ".", 1);
32193 }
32194 sqlite3_str_appendall(pAccum, pItem->zName);
32195 }else if( pItem->zAlias ){
32196 sqlite3_str_appendall(pAccum, pItem->zAlias);
32197 }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */
32198 Select *pSel = pItem->u4.pSubq->pSelect;
32199 assert( pSel!=0 );
32200 if( pSel->selFlags & SF_NestedFrom ){
32201 sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
32202 }else if( pSel->selFlags & SF_MultiValue ){
32203 assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy );
32204 sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE",
@@ -32808,13 +32976,13 @@
32976 int n = 0;
32977 char zLine[1000];
32978 sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
32979 x.printfFlags |= SQLITE_PRINTF_INTERNAL;
32980 sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
32981 if( pItem->pSTab ){
32982 sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s",
32983 pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab,
32984 pItem->colUsed,
32985 pItem->fg.rowidUsed ? "+rowid" : "");
32986 }
32987 if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
32988 sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
@@ -32841,27 +33009,34 @@
33009 if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
33010 if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
33011 if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
33012 if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
33013 if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
33014 if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema");
33015 if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema");
33016 if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery");
33017
33018 sqlite3StrAccumFinish(&x);
33019 sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
33020 n = 0;
33021 if( pItem->fg.isSubquery ) n++;
33022 if( pItem->fg.isTabFunc ) n++;
33023 if( pItem->fg.isUsing ) n++;
33024 if( pItem->fg.isUsing ){
33025 sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
33026 }
33027 if( pItem->fg.isSubquery ){
33028 assert( n==1 );
33029 if( pItem->pSTab ){
33030 Table *pTab = pItem->pSTab;
33031 sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
33032 }
33033 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
33034 sqlite3TreeViewPush(&pView, 0);
33035 sqlite3TreeViewLine(pView, "SUBQUERY");
33036 sqlite3TreeViewPop(&pView);
33037 sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
33038 }
33039 if( pItem->fg.isTabFunc ){
33040 sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
33041 }
33042 sqlite3TreeViewPop(&pView);
@@ -38721,11 +38896,11 @@
38896 ** Allowed values for the unixFile.ctrlFlags bitmask:
38897 */
38898 #define UNIXFILE_EXCL 0x01 /* Connections from one process only */
38899 #define UNIXFILE_RDONLY 0x02 /* Connection is read only */
38900 #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
38901 #if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX)
38902 # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */
38903 #else
38904 # define UNIXFILE_DIRSYNC 0x00
38905 #endif
38906 #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@@ -76573,11 +76748,11 @@
76748 }
76749 if( pCur->iPage>0
76750 && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
76751 && pIdxKey->errCode==SQLITE_OK
76752 ){
76753 pCur->curFlags &= ~(BTCF_ValidOvfl|BTCF_AtLast);
76754 if( !pCur->pPage->isInit ){
76755 return SQLITE_CORRUPT_BKPT;
76756 }
76757 goto bypass_moveto_root; /* Start search on the current page */
76758 }
@@ -95267,11 +95442,11 @@
95442 }
95443 break;
95444 }
95445 #endif
95446
95447 #if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE)
95448 /* Opcode: Cast P1 P2 * * *
95449 ** Synopsis: affinity(r[P1])
95450 **
95451 ** Force the value in register P1 to be the type defined by P2.
95452 **
@@ -102547,10 +102722,15 @@
102722 }
102723 if( pTab && !HasRowid(pTab) ){
102724 pTab = 0;
102725 sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
102726 }
102727 if( pTab && (pTab->tabFlags&TF_HasGenerated)!=0 ){
102728 pTab = 0;
102729 sqlite3ErrorMsg(&sParse, "cannot open table with generated columns: %s",
102730 zTable);
102731 }
102732 #ifndef SQLITE_OMIT_VIEW
102733 if( pTab && IsView(pTab) ){
102734 pTab = 0;
102735 sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
102736 }
@@ -106731,11 +106911,13 @@
106911 SrcItem *pItem;
106912
106913 pSrc = p->pSrc;
106914 if( ALWAYS(pSrc) ){
106915 for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
106916 if( pItem->fg.isSubquery
106917 && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect)
106918 ){
106919 return WRC_Abort;
106920 }
106921 if( pItem->fg.isTabFunc
106922 && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
106923 ){
@@ -107037,11 +107219,11 @@
107219 ){
107220 Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
107221 if( pNew ){
107222 pNew->iTable = pMatch->iCursor;
107223 pNew->iColumn = iColumn;
107224 pNew->y.pTab = pMatch->pSTab;
107225 assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
107226 ExprSetProperty(pNew, EP_CanBeNull);
107227 *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
107228 }
107229 }
@@ -107168,24 +107350,28 @@
107350 SrcList *pSrcList = pNC->pSrcList;
107351
107352 if( pSrcList ){
107353 for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
107354 u8 hCol;
107355 pTab = pItem->pSTab;
107356 assert( pTab!=0 && pTab->zName!=0 );
107357 assert( pTab->nCol>0 || pParse->nErr );
107358 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem));
107359 if( pItem->fg.isNestedFrom ){
107360 /* In this case, pItem is a subquery that has been formed from a
107361 ** parenthesized subset of the FROM clause terms. Example:
107362 ** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
107363 ** \_________________________/
107364 ** This pItem -------------^
107365 */
107366 int hit = 0;
107367 Select *pSel;
107368 assert( pItem->fg.isSubquery );
107369 assert( pItem->u4.pSubq!=0 );
107370 pSel = pItem->u4.pSubq->pSelect;
107371 assert( pSel!=0 );
107372 pEList = pSel->pEList;
107373 assert( pEList!=0 );
107374 assert( pEList->nExpr==pTab->nCol );
107375 for(j=0; j<pEList->nExpr; j++){
107376 int bRowid = 0; /* True if possible rowid match */
107377 if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
@@ -107305,12 +107491,12 @@
107491 ** words non-VIEW candidate terms take precedence over VIEWs.
107492 */
107493 if( cntTab==0
107494 || (cntTab==1
107495 && ALWAYS(pMatch!=0)
107496 && ALWAYS(pMatch->pSTab!=0)
107497 && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0
107498 && (pTab->tabFlags & TF_Ephemeral)==0)
107499 ){
107500 cntTab = 1;
107501 pMatch = pItem;
107502 }else{
@@ -107327,11 +107513,11 @@
107513 }
107514 }
107515 if( pMatch ){
107516 pExpr->iTable = pMatch->iCursor;
107517 assert( ExprUseYTab(pExpr) );
107518 pExpr->y.pTab = pMatch->pSTab;
107519 if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
107520 ExprSetProperty(pExpr, EP_CanBeNull);
107521 }
107522 pSchema = pExpr->y.pTab->pSchema;
107523 }
@@ -107369,11 +107555,11 @@
107555 #endif /* SQLITE_OMIT_TRIGGER */
107556 #ifndef SQLITE_OMIT_UPSERT
107557 if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
107558 Upsert *pUpsert = pNC->uNC.pUpsert;
107559 if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
107560 pTab = pUpsert->pUpsertSrc->a[0].pSTab;
107561 pExpr->iTable = EXCLUDED_TABLE_NUMBER;
107562 }
107563 }
107564 #endif /* SQLITE_OMIT_UPSERT */
107565
@@ -107452,15 +107638,15 @@
107638 if( cnt==0
107639 && cntTab>=1
107640 && pMatch
107641 && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
107642 && sqlite3IsRowid(zCol)
107643 && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom)
107644 ){
107645 cnt = cntTab;
107646 #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2
107647 if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){
107648 eNewExprOp = TK_NULL;
107649 }
107650 #endif
107651 if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
107652 pExpr->affExpr = SQLITE_AFF_INTEGER;
@@ -107693,11 +107879,11 @@
107879 Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
107880 if( p ){
107881 SrcItem *pItem = &pSrc->a[iSrc];
107882 Table *pTab;
107883 assert( ExprUseYTab(p) );
107884 pTab = p->y.pTab = pItem->pSTab;
107885 p->iTable = pItem->iCursor;
107886 if( p->y.pTab->iPKey==iCol ){
107887 p->iColumn = -1;
107888 }else{
107889 p->iColumn = (ynVar)iCol;
@@ -107812,11 +107998,11 @@
107998 SrcItem *pItem;
107999 assert( pSrcList && pSrcList->nSrc>=1 );
108000 pItem = pSrcList->a;
108001 pExpr->op = TK_COLUMN;
108002 assert( ExprUseYTab(pExpr) );
108003 pExpr->y.pTab = pItem->pSTab;
108004 pExpr->iTable = pItem->iCursor;
108005 pExpr->iColumn--;
108006 pExpr->affExpr = SQLITE_AFF_INTEGER;
108007 break;
108008 }
@@ -108118,13 +108304,13 @@
108304 assert( pExpr->pLeft->op==TK_ORDER );
108305 assert( ExprUseXList(pExpr->pLeft) );
108306 sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
108307 }
108308 #ifndef SQLITE_OMIT_WINDOWFUNC
108309 if( pWin && pParse->nErr==0 ){
108310 Select *pSel = pNC->pWinSelect;
108311 assert( ExprUseYWin(pExpr) && pWin==pExpr->y.pWin );
108312 if( IN_RENAME_OBJECT==0 ){
108313 sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
108314 if( pParse->db->mallocFailed ) break;
108315 }
108316 sqlite3WalkExprList(pWalker, pWin->pPartition);
@@ -108702,11 +108888,15 @@
108888 ** In this case the ORDER BY clause (p->pOrderBy) should be resolved
108889 ** as if it were part of the sub-query, not the parent. This block
108890 ** moves the pOrderBy down to the sub-query. It will be moved back
108891 ** after the names have been resolved. */
108892 if( p->selFlags & SF_Converted ){
108893 Select *pSub;
108894 assert( p->pSrc->a[0].fg.isSubquery );
108895 assert( p->pSrc->a[0].u4.pSubq!=0 );
108896 pSub = p->pSrc->a[0].u4.pSubq->pSelect;
108897 assert( pSub!=0 );
108898 assert( p->pSrc->nSrc==1 && p->pOrderBy );
108899 assert( pSub->pPrior && pSub->pOrderBy==0 );
108900 pSub->pOrderBy = p->pOrderBy;
108901 p->pOrderBy = 0;
108902 }
@@ -108714,17 +108904,20 @@
108904 /* Recursively resolve names in all subqueries in the FROM clause
108905 */
108906 if( pOuterNC ) pOuterNC->nNestedSelect++;
108907 for(i=0; i<p->pSrc->nSrc; i++){
108908 SrcItem *pItem = &p->pSrc->a[i];
108909 assert( pItem->zName!=0
108910 || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/
108911 if( pItem->fg.isSubquery
108912 && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0
108913 ){
108914 int nRef = pOuterNC ? pOuterNC->nRef : 0;
108915 const char *zSavedContext = pParse->zAuthContext;
108916
108917 if( pItem->zName ) pParse->zAuthContext = pItem->zName;
108918 sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC);
108919 pParse->zAuthContext = zSavedContext;
108920 if( pParse->nErr ) return WRC_Abort;
108921 assert( db->mallocFailed==0 );
108922
108923 /* If the number of references to the outer context changed when
@@ -108822,11 +109015,14 @@
109015 ** the sub-query back to the parent query. At this point each term
109016 ** within the ORDER BY clause has been transformed to an integer value.
109017 ** These integers will be replaced by copies of the corresponding result
109018 ** set expressions by the call to resolveOrderGroupBy() below. */
109019 if( p->selFlags & SF_Converted ){
109020 Select *pSub;
109021 assert( p->pSrc->a[0].fg.isSubquery );
109022 pSub = p->pSrc->a[0].u4.pSubq->pSelect;
109023 assert( pSub!=0 );
109024 p->pOrderBy = pSub->pOrderBy;
109025 pSub->pOrderBy = 0;
109026 }
109027
109028 /* Process the ORDER BY clause for singleton SELECT statements.
@@ -109089,11 +109285,11 @@
109285 memset(&sNC, 0, sizeof(sNC));
109286 memset(&sSrc, 0, sizeof(sSrc));
109287 if( pTab ){
109288 sSrc.nSrc = 1;
109289 sSrc.a[0].zName = pTab->zName;
109290 sSrc.a[0].pSTab = pTab;
109291 sSrc.a[0].iCursor = -1;
109292 if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
109293 /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
109294 ** schema elements */
109295 type |= NC_FromDDL;
@@ -110986,19 +111182,34 @@
111182 pNew->nSrc = pNew->nAlloc = p->nSrc;
111183 for(i=0; i<p->nSrc; i++){
111184 SrcItem *pNewItem = &pNew->a[i];
111185 const SrcItem *pOldItem = &p->a[i];
111186 Table *pTab;
111187 pNewItem->fg = pOldItem->fg;
111188 if( pOldItem->fg.isSubquery ){
111189 Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery));
111190 if( pNewSubq==0 ){
111191 assert( db->mallocFailed );
111192 pNewItem->fg.isSubquery = 0;
111193 }else{
111194 memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq));
111195 pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags);
111196 if( pNewSubq->pSelect==0 ){
111197 sqlite3DbFree(db, pNewSubq);
111198 pNewSubq = 0;
111199 pNewItem->fg.isSubquery = 0;
111200 }
111201 }
111202 pNewItem->u4.pSubq = pNewSubq;
111203 }else if( pOldItem->fg.fixedSchema ){
111204 pNewItem->u4.pSchema = pOldItem->u4.pSchema;
111205 }else{
111206 pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase);
111207 }
111208 pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
111209 pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
 
111210 pNewItem->iCursor = pOldItem->iCursor;
 
 
 
111211 if( pNewItem->fg.isIndexedBy ){
111212 pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
111213 }else if( pNewItem->fg.isTabFunc ){
111214 pNewItem->u1.pFuncArg =
111215 sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
@@ -111007,15 +111218,14 @@
111218 }
111219 pNewItem->u2 = pOldItem->u2;
111220 if( pNewItem->fg.isCte ){
111221 pNewItem->u2.pCteUse->nUse++;
111222 }
111223 pTab = pNewItem->pSTab = pOldItem->pSTab;
111224 if( pTab ){
111225 pTab->nTabRef++;
111226 }
 
111227 if( pOldItem->fg.isUsing ){
111228 assert( pNewItem->fg.isUsing );
111229 pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
111230 }else{
111231 pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
@@ -111085,11 +111295,10 @@
111295 }
111296 *pp = pNew;
111297 pp = &pNew->pPrior;
111298 pNext = pNew;
111299 }
 
111300 return pRet;
111301 }
111302 #else
111303 SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){
111304 assert( p==0 );
@@ -112105,12 +112314,12 @@
112314 if( p->pLimit ) return 0; /* Has no LIMIT clause */
112315 if( p->pWhere ) return 0; /* Has no WHERE clause */
112316 pSrc = p->pSrc;
112317 assert( pSrc!=0 );
112318 if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
112319 if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */
112320 pTab = pSrc->a[0].pSTab;
112321 assert( pTab!=0 );
112322 assert( !IsView(pTab) ); /* FROM clause is not a view */
112323 if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
112324 pEList = p->pEList;
112325 assert( pEList!=0 );
@@ -112289,11 +112498,11 @@
112498 int nExpr = pEList->nExpr;
112499
112500 assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
112501 assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
112502 assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
112503 pTab = p->pSrc->a[0].pSTab;
112504
112505 /* Code an OP_Transaction and OP_TableLock for <table>. */
112506 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
112507 assert( iDb>=0 && iDb<SQLITE_MAX_DB );
112508 sqlite3CodeVerifySchema(pParse, iDb);
@@ -117727,12 +117936,13 @@
117936 }
117937 if( pStep->pFrom ){
117938 int i;
117939 for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
117940 SrcItem *p = &pStep->pFrom->a[i];
117941 if( p->fg.isSubquery ){
117942 assert( p->u4.pSubq!=0 );
117943 sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0);
117944 }
117945 }
117946 }
117947
117948 if( db->mallocFailed ){
@@ -117796,12 +118006,16 @@
118006 sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
118007 sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
118008 }
118009 if( pStep->pFrom ){
118010 int i;
118011 SrcList *pFrom = pStep->pFrom;
118012 for(i=0; i<pFrom->nSrc; i++){
118013 if( pFrom->a[i].fg.isSubquery ){
118014 assert( pFrom->a[i].u4.pSubq!=0 );
118015 sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect);
118016 }
118017 }
118018 }
118019 }
118020 }
118021
@@ -118044,11 +118258,11 @@
118258 assert( pWalker->pParse->db->mallocFailed );
118259 return WRC_Abort;
118260 }
118261 for(i=0; i<pSrc->nSrc; i++){
118262 SrcItem *pItem = &pSrc->a[i];
118263 if( pItem->pSTab==p->pTab ){
118264 renameTokenFind(pWalker->pParse, p, pItem->zName);
118265 }
118266 }
118267 renameWalkWith(pWalker, pSelect);
118268
@@ -121178,24 +121392,25 @@
121392 int iDb = sqlite3FindDbName(db, pFix->zDb);
121393 SrcList *pList = pSelect->pSrc;
121394
121395 if( NEVER(pList==0) ) return WRC_Continue;
121396 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
121397 if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){
121398 if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
121399 if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){
121400 sqlite3ErrorMsg(pFix->pParse,
121401 "%s %T cannot reference objects in database %s",
121402 pFix->zType, pFix->pName, pItem->u4.zDatabase);
121403 return WRC_Abort;
121404 }
121405 sqlite3DbFree(db, pItem->u4.zDatabase);
 
121406 pItem->fg.notCte = 1;
121407 pItem->fg.hadSchema = 1;
121408 }
121409 pItem->u4.pSchema = pFix->pSchema;
121410 pItem->fg.fromDDL = 1;
121411 pItem->fg.fixedSchema = 1;
121412 }
121413 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
121414 if( pList->a[i].fg.isUsing==0
121415 && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
121416 ){
@@ -121484,11 +121699,11 @@
121699 pTab = pParse->pTriggerTab;
121700 }else{
121701 assert( pTabList );
121702 for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
121703 if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
121704 pTab = pTabList->a[iSrc].pSTab;
121705 break;
121706 }
121707 }
121708 }
121709 iCol = pExpr->iColumn;
@@ -122087,16 +122302,16 @@
122302 Parse *pParse,
122303 u32 flags,
122304 SrcItem *p
122305 ){
122306 const char *zDb;
122307 if( p->fg.fixedSchema ){
122308 int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema);
 
122309 zDb = pParse->db->aDb[iDb].zDbSName;
122310 }else{
122311 assert( !p->fg.isSubquery );
122312 zDb = p->u4.zDatabase;
122313 }
122314 return sqlite3LocateTable(pParse, flags, p->zName, zDb);
122315 }
122316
122317 /*
@@ -125077,19 +125292,21 @@
125292 if( db->mallocFailed ){
125293 goto exit_drop_table;
125294 }
125295 assert( pParse->nErr==0 );
125296 assert( pName->nSrc==1 );
125297 assert( pName->a[0].fg.fixedSchema==0 );
125298 assert( pName->a[0].fg.isSubquery==0 );
125299 if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
125300 if( noErr ) db->suppressErr++;
125301 assert( isView==0 || isView==LOCATE_VIEW );
125302 pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
125303 if( noErr ) db->suppressErr--;
125304
125305 if( pTab==0 ){
125306 if( noErr ){
125307 sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
125308 sqlite3ForceNotReadOnly(pParse);
125309 }
125310 goto exit_drop_table;
125311 }
125312 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -126176,19 +126393,21 @@
126393 if( db->mallocFailed ){
126394 goto exit_drop_index;
126395 }
126396 assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
126397 assert( pName->nSrc==1 );
126398 assert( pName->a[0].fg.fixedSchema==0 );
126399 assert( pName->a[0].fg.isSubquery==0 );
126400 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
126401 goto exit_drop_index;
126402 }
126403 pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase);
126404 if( pIndex==0 ){
126405 if( !ifExists ){
126406 sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
126407 }else{
126408 sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase);
126409 sqlite3ForceNotReadOnly(pParse);
126410 }
126411 pParse->checkSchema = 1;
126412 goto exit_drop_index;
126413 }
@@ -126481,16 +126700,18 @@
126700 }
126701 pItem = &pList->a[pList->nSrc-1];
126702 if( pDatabase && pDatabase->z==0 ){
126703 pDatabase = 0;
126704 }
126705 assert( pItem->fg.fixedSchema==0 );
126706 assert( pItem->fg.isSubquery==0 );
126707 if( pDatabase ){
126708 pItem->zName = sqlite3NameFromToken(db, pDatabase);
126709 pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable);
126710 }else{
126711 pItem->zName = sqlite3NameFromToken(db, pTable);
126712 pItem->u4.zDatabase = 0;
126713 }
126714 return pList;
126715 }
126716
126717 /*
@@ -126502,16 +126723,43 @@
126723 assert( pList || pParse->db->mallocFailed );
126724 if( ALWAYS(pList) ){
126725 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
126726 if( pItem->iCursor>=0 ) continue;
126727 pItem->iCursor = pParse->nTab++;
126728 if( pItem->fg.isSubquery ){
126729 assert( pItem->u4.pSubq!=0 );
126730 assert( pItem->u4.pSubq->pSelect!=0 );
126731 assert( pItem->u4.pSubq->pSelect->pSrc!=0 );
126732 sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc);
126733 }
126734 }
126735 }
126736 }
126737
126738 /*
126739 ** Delete a Subquery object and its substructure.
126740 */
126741 SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){
126742 assert( pSubq!=0 && pSubq->pSelect!=0 );
126743 sqlite3SelectDelete(db, pSubq->pSelect);
126744 sqlite3DbFree(db, pSubq);
126745 }
126746
126747 /*
126748 ** Remove a Subquery from a SrcItem. Return the associated Select object.
126749 ** The returned Select becomes the responsibility of the caller.
126750 */
126751 SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){
126752 Select *pSel;
126753 assert( pItem!=0 );
126754 assert( pItem->fg.isSubquery );
126755 pSel = pItem->u4.pSubq->pSelect;
126756 sqlite3DbFree(db, pItem->u4.pSubq);
126757 pItem->u4.pSubq = 0;
126758 pItem->fg.isSubquery = 0;
126759 return pSel;
126760 }
126761
126762 /*
126763 ** Delete an entire SrcList including all its substructure.
126764 */
126765 SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
@@ -126518,25 +126766,84 @@
126766 int i;
126767 SrcItem *pItem;
126768 assert( db!=0 );
126769 if( pList==0 ) return;
126770 for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
126771
126772 /* Check invariants on SrcItem */
126773 assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc );
126774 assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy );
126775 assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery );
126776 assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 &&
126777 pItem->u4.pSubq->pSelect!=0) );
126778
126779 if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
126780 if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
126781 if( pItem->fg.isSubquery ){
126782 sqlite3SubqueryDelete(db, pItem->u4.pSubq);
126783 }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){
126784 sqlite3DbNNFreeNN(db, pItem->u4.zDatabase);
126785 }
126786 if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
126787 if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
126788 sqlite3DeleteTable(db, pItem->pSTab);
 
126789 if( pItem->fg.isUsing ){
126790 sqlite3IdListDelete(db, pItem->u3.pUsing);
126791 }else if( pItem->u3.pOn ){
126792 sqlite3ExprDelete(db, pItem->u3.pOn);
126793 }
126794 }
126795 sqlite3DbNNFreeNN(db, pList);
126796 }
126797
126798 /*
126799 ** Attach a Subquery object to pItem->uv.pSubq. Set the
126800 ** pSelect value but leave all the other values initialized
126801 ** to zero.
126802 **
126803 ** A copy of the Select object is made if dupSelect is true, and the
126804 ** SrcItem takes responsibility for deleting the copy. If dupSelect is
126805 ** false, ownership of the Select passes to the SrcItem. Either way,
126806 ** the SrcItem will take responsibility for deleting the Select.
126807 **
126808 ** When dupSelect is zero, that means the Select might get deleted right
126809 ** away if there is an OOM error. Beware.
126810 **
126811 ** Return non-zero on success. Return zero on an OOM error.
126812 */
126813 SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(
126814 Parse *pParse, /* Parsing context */
126815 SrcItem *pItem, /* Item to which the subquery is to be attached */
126816 Select *pSelect, /* The subquery SELECT. Must be non-NULL */
126817 int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/
126818 ){
126819 Subquery *p;
126820 assert( pSelect!=0 );
126821 assert( pItem->fg.isSubquery==0 );
126822 if( pItem->fg.fixedSchema ){
126823 pItem->u4.pSchema = 0;
126824 pItem->fg.fixedSchema = 0;
126825 }else if( pItem->u4.zDatabase!=0 ){
126826 sqlite3DbFree(pParse->db, pItem->u4.zDatabase);
126827 pItem->u4.zDatabase = 0;
126828 }
126829 if( dupSelect ){
126830 pSelect = sqlite3SelectDup(pParse->db, pSelect, 0);
126831 if( pSelect==0 ) return 0;
126832 }
126833 p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery));
126834 if( p==0 ){
126835 sqlite3SelectDelete(pParse->db, pSelect);
126836 return 0;
126837 }
126838 pItem->fg.isSubquery = 1;
126839 p->pSelect = pSelect;
126840 assert( offsetof(Subquery, pSelect)==0 );
126841 memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect));
126842 return 1;
126843 }
126844
126845
126846 /*
126847 ** This routine is called by the parser to add a new term to the
126848 ** end of a growing FROM clause. The "p" parameter is the part of
126849 ** the FROM clause that has already been constructed. "p" is NULL
@@ -126583,14 +126890,16 @@
126890 }
126891 assert( pAlias!=0 );
126892 if( pAlias->n ){
126893 pItem->zAlias = sqlite3NameFromToken(db, pAlias);
126894 }
126895 assert( pSubquery==0 || pDatabase==0 );
126896 if( pSubquery ){
126897 if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){
126898 if( pSubquery->selFlags & SF_NestedFrom ){
126899 pItem->fg.isNestedFrom = 1;
126900 }
126901 }
126902 }
126903 assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
126904 assert( pItem->fg.isUsing==0 );
126905 if( pOnUsing==0 ){
@@ -127864,21 +128173,21 @@
128173 ** return a pointer. Set an error message and return NULL if the table
128174 ** name is not found or if any other error occurs.
128175 **
128176 ** The following fields are initialized appropriate in pSrc:
128177 **
128178 ** pSrc->a[0].spTab Pointer to the Table object
128179 ** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one
128180 **
128181 */
128182 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
128183 SrcItem *pItem = pSrc->a;
128184 Table *pTab;
128185 assert( pItem && pSrc->nSrc>=1 );
128186 pTab = sqlite3LocateTableItem(pParse, 0, pItem);
128187 if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab);
128188 pItem->pSTab = pTab;
128189 pItem->fg.notCte = 1;
128190 if( pTab ){
128191 pTab->nTabRef++;
128192 if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
128193 pTab = 0;
@@ -127996,11 +128305,12 @@
128305 pWhere = sqlite3ExprDup(db, pWhere, 0);
128306 pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0);
128307 if( pFrom ){
128308 assert( pFrom->nSrc==1 );
128309 pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
128310 assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 );
128311 pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
128312 assert( pFrom->a[0].fg.isUsing==0 );
128313 assert( pFrom->a[0].u3.pOn==0 );
128314 }
128315 pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
128316 SF_IncludeHidden, pLimit);
@@ -128058,11 +128368,11 @@
128368 ** DELETE FROM table_a WHERE rowid IN (
128369 ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
128370 ** );
128371 */
128372
128373 pTab = pSrc->a[0].pSTab;
128374 if( HasRowid(pTab) ){
128375 pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
128376 pEList = sqlite3ExprListAppend(
128377 pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
128378 );
@@ -128091,13 +128401,13 @@
128401 }
128402 }
128403
128404 /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
128405 ** and the SELECT subtree. */
128406 pSrc->a[0].pSTab = 0;
128407 pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
128408 pSrc->a[0].pSTab = pTab;
128409 if( pSrc->a[0].fg.isIndexedBy ){
128410 assert( pSrc->a[0].fg.isCte==0 );
128411 pSrc->a[0].u2.pIBIndex = 0;
128412 pSrc->a[0].fg.isIndexedBy = 0;
128413 sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
@@ -130920,11 +131230,15 @@
131230
131231 /*
131232 ** group_concat(EXPR, ?SEPARATOR?)
131233 ** string_agg(EXPR, SEPARATOR)
131234 **
131235 ** Content is accumulated in GroupConcatCtx.str with the SEPARATOR
131236 ** coming before the EXPR value, except for the first entry which
131237 ** omits the SEPARATOR.
131238 **
131239 ** It is tragic that the SEPARATOR goes before the EXPR string. The
131240 ** groupConcatInverse() implementation would have been easier if the
131241 ** SEPARATOR were appended after EXPR. And the order is undocumented,
131242 ** so we could change it, in theory. But the old behavior has been
131243 ** around for so long that we dare not, for fear of breaking something.
131244 */
@@ -131024,11 +131338,11 @@
131338 if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
131339 pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
131340 /* pGCC is always non-NULL since groupConcatStep() will have always
131341 ** run first to initialize it */
131342 if( ALWAYS(pGCC) ){
131343 int nVS; /* Number of characters to remove */
131344 /* Must call sqlite3_value_text() to convert the argument into text prior
131345 ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
131346 (void)sqlite3_value_text(argv[0]);
131347 nVS = sqlite3_value_bytes(argv[0]);
131348 pGCC->nAccum -= 1;
@@ -132675,13 +132989,13 @@
132989 /* Create a SrcList structure containing the child table. We need the
132990 ** child table as a SrcList for sqlite3WhereBegin() */
132991 pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
132992 if( pSrc ){
132993 SrcItem *pItem = pSrc->a;
132994 pItem->pSTab = pFKey->pFrom;
132995 pItem->zName = pFKey->pFrom->zName;
132996 pItem->pSTab->nTabRef++;
132997 pItem->iCursor = pParse->nTab++;
132998
132999 if( regNew!=0 ){
133000 fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
133001 }
@@ -132969,11 +133283,12 @@
133283 }
133284 pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
133285 if( pSrc ){
133286 assert( pSrc->nSrc==1 );
133287 pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
133288 assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 );
133289 pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
133290 }
133291 pSelect = sqlite3SelectNew(pParse,
133292 sqlite3ExprListAppend(pParse, 0, pRaise),
133293 pSrc,
133294 pWhere,
@@ -133703,12 +134018,15 @@
134018 ** co-routine.
134019 */
134020 SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){
134021 if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){
134022 SrcItem *pItem = &pVal->pSrc->a[0];
134023 assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr );
134024 if( pItem->fg.isSubquery ){
134025 sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn);
134026 sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1);
134027 }
134028 }
134029 }
134030
134031 /*
134032 ** Return true if all expressions in the expression-list passed as the
@@ -133832,56 +134150,67 @@
134150 sqlite3ReadSchema(pParse);
134151 }
134152
134153 if( pRet ){
134154 SelectDest dest;
134155 Subquery *pSubq;
134156 pRet->pSrc->nSrc = 1;
134157 pRet->pPrior = pLeft->pPrior;
134158 pRet->op = pLeft->op;
134159 if( pRet->pPrior ) pRet->selFlags |= SF_Values;
134160 pLeft->pPrior = 0;
134161 pLeft->op = TK_SELECT;
134162 assert( pLeft->pNext==0 );
134163 assert( pRet->pNext==0 );
134164 p = &pRet->pSrc->a[0];
 
134165 p->fg.viaCoroutine = 1;
 
 
134166 p->iCursor = -1;
134167 assert( !p->fg.isIndexedBy && !p->fg.isTabFunc );
134168 p->u1.nRow = 2;
134169 if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){
134170 pSubq = p->u4.pSubq;
134171 pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1;
134172 pSubq->regReturn = ++pParse->nMem;
134173 sqlite3VdbeAddOp3(v, OP_InitCoroutine,
134174 pSubq->regReturn, 0, pSubq->addrFillSub);
134175 sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
134176
134177 /* Allocate registers for the output of the co-routine. Do so so
134178 ** that there are two unused registers immediately before those
134179 ** used by the co-routine. This allows the code in sqlite3Insert()
134180 ** to use these registers directly, instead of copying the output
134181 ** of the co-routine to a separate array for processing. */
134182 dest.iSdst = pParse->nMem + 3;
134183 dest.nSdst = pLeft->pEList->nExpr;
134184 pParse->nMem += 2 + dest.nSdst;
134185
134186 pLeft->selFlags |= SF_MultiValue;
134187 sqlite3Select(pParse, pLeft, &dest);
134188 pSubq->regResult = dest.iSdst;
134189 assert( pParse->nErr || dest.iSdst>0 );
134190 }
134191 pLeft = pRet;
134192 }
134193 }else{
134194 p = &pLeft->pSrc->a[0];
134195 assert( !p->fg.isTabFunc && !p->fg.isIndexedBy );
134196 p->u1.nRow++;
134197 }
134198
134199 if( pParse->nErr==0 ){
134200 Subquery *pSubq;
134201 assert( p!=0 );
134202 assert( p->fg.isSubquery );
134203 pSubq = p->u4.pSubq;
134204 assert( pSubq!=0 );
134205 assert( pSubq->pSelect!=0 );
134206 assert( pSubq->pSelect->pEList!=0 );
134207 if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){
134208 sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect);
134209 }else{
134210 sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0);
134211 sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn);
134212 }
134213 }
134214 sqlite3ExprListDelete(pParse->db, pRow);
134215 }
134216
@@ -134228,13 +134557,18 @@
134557 if( pSelect->pSrc->nSrc==1
134558 && pSelect->pSrc->a[0].fg.viaCoroutine
134559 && pSelect->pPrior==0
134560 ){
134561 SrcItem *pItem = &pSelect->pSrc->a[0];
134562 Subquery *pSubq;
134563 assert( pItem->fg.isSubquery );
134564 pSubq = pItem->u4.pSubq;
134565 dest.iSDParm = pSubq->regReturn;
134566 regFromSelect = pSubq->regResult;
134567 assert( pSubq->pSelect!=0 );
134568 assert( pSubq->pSelect->pEList!=0 );
134569 nColumn = pSubq->pSelect->pEList->nExpr;
134570 ExplainQueryPlan((pParse, 0, "SCAN %S", pItem));
134571 if( bIdListInOrder && nColumn==pTab->nCol ){
134572 regData = regFromSelect;
134573 regRowid = regData - 1;
134574 regIns = regRowid - (IsVirtual(pTab) ? 1 : 0);
@@ -136150,11 +136484,11 @@
136484 }
136485 assert(pSelect->pSrc); /* allocated even if there is no FROM clause */
136486 if( pSelect->pSrc->nSrc!=1 ){
136487 return 0; /* FROM clause must have exactly one term */
136488 }
136489 if( pSelect->pSrc->a[0].fg.isSubquery ){
136490 return 0; /* FROM clause cannot contain a subquery */
136491 }
136492 if( pSelect->pWhere ){
136493 return 0; /* SELECT may not have a WHERE clause */
136494 }
@@ -143448,15 +143782,17 @@
143782 /*
143783 ** Mark a subquery result column as having been used.
143784 */
143785 SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
143786 assert( pItem!=0 );
143787 assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
143788 if( pItem->fg.isNestedFrom ){
143789 ExprList *pResults;
143790 assert( pItem->fg.isSubquery );
143791 assert( pItem->u4.pSubq!=0 );
143792 assert( pItem->u4.pSubq->pSelect!=0 );
143793 pResults = pItem->u4.pSubq->pSelect->pEList;
143794 assert( pResults!=0 );
143795 assert( iCol>=0 && iCol<pResults->nExpr );
143796 pResults->a[iCol].fg.bUsed = 1;
143797 }
143798 }
@@ -143486,13 +143822,13 @@
143822 assert( iEnd<pSrc->nSrc );
143823 assert( iStart>=0 );
143824 assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
143825
143826 for(i=iStart; i<=iEnd; i++){
143827 iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol);
143828 if( iCol>=0
143829 && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0)
143830 ){
143831 if( piTab ){
143832 sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
143833 *piTab = i;
143834 *piCol = iCol;
@@ -143617,14 +143953,14 @@
143953
143954 pSrc = p->pSrc;
143955 pLeft = &pSrc->a[0];
143956 pRight = &pLeft[1];
143957 for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
143958 Table *pRightTab = pRight->pSTab;
143959 u32 joinType;
143960
143961 if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue;
143962 joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
143963
143964 /* If this is a NATURAL join, synthesize an appropriate USING clause
143965 ** to specify which columns should be joined.
143966 */
@@ -145046,12 +145382,16 @@
145382 int iCol = pExpr->iColumn; /* Index of column in pTab */
145383 while( pNC && !pTab ){
145384 SrcList *pTabList = pNC->pSrcList;
145385 for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
145386 if( j<pTabList->nSrc ){
145387 pTab = pTabList->a[j].pSTab;
145388 if( pTabList->a[j].fg.isSubquery ){
145389 pS = pTabList->a[j].u4.pSubq->pSelect;
145390 }else{
145391 pS = 0;
145392 }
145393 }else{
145394 pNC = pNC->pNext;
145395 }
145396 }
145397
@@ -147099,11 +147439,13 @@
147439 p->pHaving = substExpr(pSubst, p->pHaving);
147440 p->pWhere = substExpr(pSubst, p->pWhere);
147441 pSrc = p->pSrc;
147442 assert( pSrc!=0 );
147443 for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
147444 if( pItem->fg.isSubquery ){
147445 substSelect(pSubst, pItem->u4.pSubq->pSelect, 1);
147446 }
147447 if( pItem->fg.isTabFunc ){
147448 substExprList(pSubst, pItem->u1.pFuncArg);
147449 }
147450 }
147451 }while( doPrior && (p = p->pPrior)!=0 );
@@ -147130,11 +147472,11 @@
147472 static void recomputeColumnsUsed(
147473 Select *pSelect, /* The complete SELECT statement */
147474 SrcItem *pSrcItem /* Which FROM clause item to recompute */
147475 ){
147476 Walker w;
147477 if( NEVER(pSrcItem->pSTab==0) ) return;
147478 memset(&w, 0, sizeof(w));
147479 w.xExprCallback = recomputeColumnsUsedExpr;
147480 w.xSelectCallback = sqlite3SelectWalkNoop;
147481 w.u.pSrcItem = pSrcItem;
147482 pSrcItem->colUsed = 0;
@@ -147170,12 +147512,14 @@
147512 assert( pItem->iCursor < aCsrMap[0] );
147513 if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){
147514 aCsrMap[pItem->iCursor+1] = pParse->nTab++;
147515 }
147516 pItem->iCursor = aCsrMap[pItem->iCursor+1];
147517 if( pItem->fg.isSubquery ){
147518 for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){
147519 srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
147520 }
147521 }
147522 }
147523 }
147524 }
147525
@@ -147482,11 +147826,12 @@
147826 if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
147827 pSrc = p->pSrc;
147828 assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
147829 pSubitem = &pSrc->a[iFrom];
147830 iParent = pSubitem->iCursor;
147831 assert( pSubitem->fg.isSubquery );
147832 pSub = pSubitem->u4.pSubq->pSelect;
147833 assert( pSub!=0 );
147834
147835 #ifndef SQLITE_OMIT_WINDOWFUNC
147836 if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */
147837 #endif
@@ -147535,11 +147880,11 @@
147880 **
147881 ** See also tickets #306, #350, and #3300.
147882 */
147883 if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
147884 if( pSubSrc->nSrc>1 /* (3a) */
147885 || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */
147886 || (p->selFlags & SF_Distinct)!=0 /* (3d) */
147887 || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
147888 ){
147889 return 0;
147890 }
@@ -147621,18 +147966,22 @@
147966 TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0);
147967 testcase( i==SQLITE_DENY );
147968 pParse->zAuthContext = zSavedAuthContext;
147969
147970 /* Delete the transient structures associated with the subquery */
147971
147972 if( ALWAYS(pSubitem->fg.isSubquery) ){
147973 pSub1 = sqlite3SubqueryDetach(db, pSubitem);
147974 }else{
147975 pSub1 = 0;
147976 }
147977 assert( pSubitem->fg.isSubquery==0 );
147978 assert( pSubitem->fg.fixedSchema==0 );
147979 sqlite3DbFree(db, pSubitem->zName);
147980 sqlite3DbFree(db, pSubitem->zAlias);
 
147981 pSubitem->zName = 0;
147982 pSubitem->zAlias = 0;
 
147983 assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
147984
147985 /* If the sub-query is a compound SELECT statement, then (by restrictions
147986 ** 17 and 18 above) it must be a UNION ALL and the parent query must
147987 ** be of the form:
@@ -147669,20 +148018,20 @@
148018 for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){
148019 Select *pNew;
148020 ExprList *pOrderBy = p->pOrderBy;
148021 Expr *pLimit = p->pLimit;
148022 Select *pPrior = p->pPrior;
148023 Table *pItemTab = pSubitem->pSTab;
148024 pSubitem->pSTab = 0;
148025 p->pOrderBy = 0;
148026 p->pPrior = 0;
148027 p->pLimit = 0;
148028 pNew = sqlite3SelectDup(db, p, 0);
148029 p->pLimit = pLimit;
148030 p->pOrderBy = pOrderBy;
148031 p->op = TK_ALL;
148032 pSubitem->pSTab = pItemTab;
148033 if( pNew==0 ){
148034 p->pPrior = pPrior;
148035 }else{
148036 pNew->selId = ++pParse->nSelect;
148037 if( aCsrMap && ALWAYS(db->mallocFailed==0) ){
@@ -147693,15 +148042,18 @@
148042 pNew->pNext = p;
148043 p->pPrior = pNew;
148044 TREETRACE(0x4,pParse,p,("compound-subquery flattener"
148045 " creates %u as peer\n",pNew->selId));
148046 }
148047 assert( pSubitem->fg.isSubquery==0 );
148048 }
148049 sqlite3DbFree(db, aCsrMap);
148050 if( db->mallocFailed ){
148051 assert( pSubitem->fg.fixedSchema==0 );
148052 assert( pSubitem->fg.isSubquery==0 );
148053 assert( pSubitem->u4.zDatabase==0 );
148054 sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0);
148055 return 1;
148056 }
148057
148058 /* Defer deleting the Table object associated with the
148059 ** subquery until code generation is
@@ -147708,20 +148060,20 @@
148060 ** complete, since there may still exist Expr.pTab entries that
148061 ** refer to the subquery even after flattening. Ticket #3346.
148062 **
148063 ** pSubitem->pTab is always non-NULL by test restrictions and tests above.
148064 */
148065 if( ALWAYS(pSubitem->pSTab!=0) ){
148066 Table *pTabToDel = pSubitem->pSTab;
148067 if( pTabToDel->nTabRef==1 ){
148068 Parse *pToplevel = sqlite3ParseToplevel(pParse);
148069 sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
148070 testcase( pToplevel->earlyCleanup );
148071 }else{
148072 pTabToDel->nTabRef--;
148073 }
148074 pSubitem->pSTab = 0;
148075 }
148076
148077 /* The following loop runs once for each term in a compound-subquery
148078 ** flattening (as described above). If we are doing a different kind
148079 ** of flattening - a flattening other than a compound-subquery flattening -
@@ -147773,12 +148125,15 @@
148125 /* Transfer the FROM clause terms from the subquery into the
148126 ** outer query.
148127 */
148128 for(i=0; i<nSubSrc; i++){
148129 SrcItem *pItem = &pSrc->a[i+iFrom];
 
148130 assert( pItem->fg.isTabFunc==0 );
148131 assert( pItem->fg.isSubquery
148132 || pItem->fg.fixedSchema
148133 || pItem->u4.zDatabase==0 );
148134 if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
148135 *pItem = pSubSrc->a[i];
148136 pItem->fg.jointype |= ltorj;
148137 iNewParent = pSubSrc->a[i].iCursor;
148138 memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
148139 }
@@ -148458,14 +148813,14 @@
148813
148814 assert( pItem!=0 );
148815 if( pItem->fg.isCorrelated || pItem->fg.isCte ){
148816 return 0;
148817 }
148818 assert( pItem->pSTab!=0 );
148819 pTab = pItem->pSTab;
148820 assert( pItem->fg.isSubquery );
148821 pSub = pItem->u4.pSubq->pSelect;
148822 assert( pSub->pEList->nExpr==pTab->nCol );
148823 for(pX=pSub; pX; pX=pX->pPrior){
148824 if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
148825 testcase( pX->selFlags & SF_Distinct );
148826 testcase( pX->selFlags & SF_Aggregate );
@@ -148590,17 +148945,17 @@
148945 assert( !p->pGroupBy );
148946
148947 if( p->pWhere
148948 || p->pEList->nExpr!=1
148949 || p->pSrc->nSrc!=1
148950 || p->pSrc->a[0].fg.isSubquery
148951 || pAggInfo->nFunc!=1
148952 || p->pHaving
148953 ){
148954 return 0;
148955 }
148956 pTab = p->pSrc->a[0].pSTab;
148957 assert( pTab!=0 );
148958 assert( !IsView(pTab) );
148959 if( !IsOrdinaryTable(pTab) ) return 0;
148960 pExpr = p->pEList->a[0].pExpr;
148961 assert( pExpr!=0 );
@@ -148621,11 +148976,11 @@
148976 ** was such a clause and the named index cannot be found, return
148977 ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
148978 ** pFrom->pIndex and return SQLITE_OK.
148979 */
148980 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
148981 Table *pTab = pFrom->pSTab;
148982 char *zIndexedBy = pFrom->u1.zIndexedBy;
148983 Index *pIdx;
148984 assert( pTab!=0 );
148985 assert( pFrom->fg.isIndexedBy!=0 );
148986
@@ -148698,11 +149053,15 @@
149053 db = pParse->db;
149054 pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
149055 if( pNew==0 ) return WRC_Abort;
149056 memset(&dummy, 0, sizeof(dummy));
149057 pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
149058 assert( pNewSrc!=0 || pParse->nErr );
149059 if( pParse->nErr ){
149060 sqlite3SrcListDelete(db, pNewSrc);
149061 return WRC_Abort;
149062 }
149063 *pNew = *p;
149064 p->pSrc = pNewSrc;
149065 p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0));
149066 p->op = TK_SELECT;
149067 p->pWhere = 0;
@@ -148753,11 +149112,11 @@
149112 SrcItem *pItem, /* FROM clause element to resolve */
149113 With **ppContext /* OUT: WITH clause return value belongs to */
149114 ){
149115 const char *zName = pItem->zName;
149116 With *p;
149117 assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 );
149118 assert( zName!=0 );
149119 for(p=pWith; p; p=p->pOuter){
149120 int i;
149121 for(i=0; i<p->nCte; i++){
149122 if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
@@ -148823,21 +149182,22 @@
149182 SrcItem *pFrom /* The FROM clause term to check */
149183 ){
149184 Cte *pCte; /* Matched CTE (or NULL if no match) */
149185 With *pWith; /* The matching WITH */
149186
149187 assert( pFrom->pSTab==0 );
149188 if( pParse->pWith==0 ){
149189 /* There are no WITH clauses in the stack. No match is possible */
149190 return 0;
149191 }
149192 if( pParse->nErr ){
149193 /* Prior errors might have left pParse->pWith in a goofy state, so
149194 ** go no further. */
149195 return 0;
149196 }
149197 assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 );
149198 if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){
149199 /* The FROM term contains a schema qualifier (ex: main.t1) and so
149200 ** it cannot possibly be a CTE reference. */
149201 return 0;
149202 }
149203 if( pFrom->fg.notCte ){
@@ -148869,11 +149229,11 @@
149229 sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
149230 return 2;
149231 }
149232 if( cannotBeFunction(pParse, pFrom) ) return 2;
149233
149234 assert( pFrom->pSTab==0 );
149235 pTab = sqlite3DbMallocZero(db, sizeof(Table));
149236 if( pTab==0 ) return 2;
149237 pCteUse = pCte->pUse;
149238 if( pCteUse==0 ){
149239 pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
@@ -148883,42 +149243,47 @@
149243 sqlite3DbFree(db, pTab);
149244 return 2;
149245 }
149246 pCteUse->eM10d = pCte->eM10d;
149247 }
149248 pFrom->pSTab = pTab;
149249 pTab->nTabRef = 1;
149250 pTab->zName = sqlite3DbStrDup(db, pCte->zName);
149251 pTab->iPKey = -1;
149252 pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
149253 pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
149254 sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1);
149255 if( db->mallocFailed ) return 2;
149256 assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
149257 pSel = pFrom->u4.pSubq->pSelect;
149258 assert( pSel!=0 );
149259 pSel->selFlags |= SF_CopyCte;
149260 if( pFrom->fg.isIndexedBy ){
149261 sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
149262 return 2;
149263 }
149264 assert( !pFrom->fg.isIndexedBy );
149265 pFrom->fg.isCte = 1;
149266 pFrom->u2.pCteUse = pCteUse;
149267 pCteUse->nUse++;
149268
149269 /* Check if this is a recursive CTE. */
149270 pRecTerm = pSel;
149271 bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
149272 while( bMayRecursive && pRecTerm->op==pSel->op ){
149273 int i;
149274 SrcList *pSrc = pRecTerm->pSrc;
149275 assert( pRecTerm->pPrior!=0 );
149276 for(i=0; i<pSrc->nSrc; i++){
149277 SrcItem *pItem = &pSrc->a[i];
149278 if( pItem->zName!=0
149279 && !pItem->fg.hadSchema
149280 && ALWAYS( !pItem->fg.isSubquery )
149281 && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0)
149282 && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
149283 ){
149284 pItem->pSTab = pTab;
149285 pTab->nTabRef++;
149286 pItem->fg.isRecursive = 1;
149287 if( pRecTerm->selFlags & SF_Recursive ){
149288 sqlite3ErrorMsg(pParse,
149289 "multiple references to recursive table: %s", pCte->zName
@@ -149016,15 +149381,18 @@
149381 ** allocates and populates the SrcItem.pTab object. If successful,
149382 ** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
149383 ** SQLITE_NOMEM.
149384 */
149385 SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
149386 Select *pSel;
149387 Table *pTab;
149388
149389 assert( pFrom->fg.isSubquery );
149390 assert( pFrom->u4.pSubq!=0 );
149391 pSel = pFrom->u4.pSubq->pSelect;
149392 assert( pSel );
149393 pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
149394 if( pTab==0 ) return SQLITE_NOMEM;
149395 pTab->nTabRef = 1;
149396 if( pFrom->zAlias ){
149397 pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
149398 }else{
@@ -149140,37 +149508,39 @@
149508 ** an entry of the FROM clause is a subquery instead of a table or view,
149509 ** then create a transient table structure to describe the subquery.
149510 */
149511 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149512 Table *pTab;
149513 assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 );
149514 if( pFrom->pSTab ) continue;
149515 assert( pFrom->fg.isRecursive==0 );
149516 if( pFrom->zName==0 ){
149517 #ifndef SQLITE_OMIT_SUBQUERY
149518 Select *pSel;
149519 assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 );
149520 pSel = pFrom->u4.pSubq->pSelect;
149521 /* A sub-query in the FROM clause of a SELECT */
149522 assert( pSel!=0 );
149523 assert( pFrom->pSTab==0 );
149524 if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
149525 if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
149526 #endif
149527 #ifndef SQLITE_OMIT_CTE
149528 }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
149529 if( rc>1 ) return WRC_Abort;
149530 pTab = pFrom->pSTab;
149531 assert( pTab!=0 );
149532 #endif
149533 }else{
149534 /* An ordinary table or view name in the FROM clause */
149535 assert( pFrom->pSTab==0 );
149536 pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
149537 if( pTab==0 ) return WRC_Abort;
149538 if( pTab->nTabRef>=0xffff ){
149539 sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
149540 pTab->zName);
149541 pFrom->pSTab = 0;
149542 return WRC_Abort;
149543 }
149544 pTab->nTabRef++;
149545 if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
149546 return WRC_Abort;
@@ -149178,19 +149548,19 @@
149548 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
149549 if( !IsOrdinaryTable(pTab) ){
149550 i16 nCol;
149551 u8 eCodeOrig = pWalker->eCode;
149552 if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
149553 assert( pFrom->fg.isSubquery==0 );
149554 if( IsView(pTab) ){
149555 if( (db->flags & SQLITE_EnableView)==0
149556 && pTab->pSchema!=db->aDb[1].pSchema
149557 ){
149558 sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
149559 pTab->zName);
149560 }
149561 sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1);
149562 }
149563 #ifndef SQLITE_OMIT_VIRTUALTABLE
149564 else if( ALWAYS(IsVirtual(pTab))
149565 && pFrom->fg.fromDDL
149566 && ALWAYS(pTab->u.vtab.p!=0)
@@ -149202,11 +149572,13 @@
149572 assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
149573 #endif
149574 nCol = pTab->nCol;
149575 pTab->nCol = -1;
149576 pWalker->eCode = 1; /* Turn on Select.selId renumbering */
149577 if( pFrom->fg.isSubquery ){
149578 sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect);
149579 }
149580 pWalker->eCode = eCodeOrig;
149581 pTab->nCol = nCol;
149582 }
149583 #endif
149584 }
@@ -149289,11 +149661,11 @@
149661 assert( ExprUseWOfst(pE) );
149662 iErrOfst = pE->w.iOfst;
149663 }
149664 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149665 int nAdd; /* Number of cols including rowid */
149666 Table *pTab = pFrom->pSTab; /* Table for this data source */
149667 ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
149668 char *zTabName; /* AS name for this data source */
149669 const char *zSchemaName = 0; /* Schema name for this data source */
149670 int iDb; /* Schema index for this data src */
149671 IdList *pUsing; /* USING clause for pFrom[1] */
@@ -149300,14 +149672,15 @@
149672
149673 if( (zTabName = pFrom->zAlias)==0 ){
149674 zTabName = pTab->zName;
149675 }
149676 if( db->mallocFailed ) break;
149677 assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) );
149678 if( pFrom->fg.isNestedFrom ){
149679 assert( pFrom->fg.isSubquery && pFrom->u4.pSubq );
149680 assert( pFrom->u4.pSubq->pSelect!=0 );
149681 pNestedFrom = pFrom->u4.pSubq->pSelect->pEList;
149682 assert( pNestedFrom!=0 );
149683 assert( pNestedFrom->nExpr==pTab->nCol );
149684 assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
149685 }else{
149686 if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
@@ -149542,18 +149915,16 @@
149915 p->selFlags |= SF_HasTypeInfo;
149916 pParse = pWalker->pParse;
149917 assert( (p->selFlags & SF_Resolved) );
149918 pTabList = p->pSrc;
149919 for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
149920 Table *pTab = pFrom->pSTab;
149921 assert( pTab!=0 );
149922 if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){
149923 /* A sub-query in the FROM clause of a SELECT */
149924 Select *pSel = pFrom->u4.pSubq->pSelect;
149925 sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
 
 
149926 }
149927 }
149928 }
149929 #endif
149930
@@ -149863,10 +150234,11 @@
150234 int i;
150235 struct AggInfo_func *pF;
150236 for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
150237 ExprList *pList;
150238 assert( ExprUseXList(pF->pFExpr) );
150239 if( pParse->nErr ) return;
150240 pList = pF->pFExpr->x.pList;
150241 if( pF->iOBTab>=0 ){
150242 /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
150243 ** were stored in emphermal table pF->iOBTab. Here, we extract those
150244 ** inputs (in ORDER BY order) and make all calls to OP_AggStep
@@ -150072,19 +150444,21 @@
150444 sqlite3ReleaseTempRange(pParse, regAgg, nArg);
150445 }
150446 if( addrNext ){
150447 sqlite3VdbeResolveLabel(v, addrNext);
150448 }
150449 if( pParse->nErr ) return;
150450 }
150451 if( regHit==0 && pAggInfo->nAccumulator ){
150452 regHit = regAcc;
150453 }
150454 if( regHit ){
150455 addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
150456 }
150457 for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
150458 sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
150459 if( pParse->nErr ) return;
150460 }
150461
150462 pAggInfo->directMode = 0;
150463 if( addrHitTest ){
150464 sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
@@ -150196,29 +150570,32 @@
150570 SrcList *pTabList, /* Search for self-joins in this FROM clause */
150571 SrcItem *pThis, /* Search for prior reference to this subquery */
150572 int iFirst, int iEnd /* Range of FROM-clause entries to search. */
150573 ){
150574 SrcItem *pItem;
150575 Select *pSel;
150576 assert( pThis->fg.isSubquery );
150577 pSel = pThis->u4.pSubq->pSelect;
150578 assert( pSel!=0 );
150579 if( pSel->selFlags & SF_PushDown ) return 0;
150580 while( iFirst<iEnd ){
150581 Select *pS1;
150582 pItem = &pTabList->a[iFirst++];
150583 if( !pItem->fg.isSubquery ) continue;
150584 if( pItem->fg.viaCoroutine ) continue;
150585 if( pItem->zName==0 ) continue;
150586 assert( pItem->pSTab!=0 );
150587 assert( pThis->pSTab!=0 );
150588 if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue;
150589 if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
150590 pS1 = pItem->u4.pSubq->pSelect;
150591 if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){
150592 /* The query flattener left two different CTE tables with identical
150593 ** names in the same FROM clause. */
150594 continue;
150595 }
150596 if( pS1->selFlags & SF_PushDown ){
150597 /* The view was modified by some other optimization such as
150598 ** pushDownWhereTerms() */
150599 continue;
150600 }
150601 return pItem;
@@ -150258,10 +150635,11 @@
150635 static int countOfViewOptimization(Parse *pParse, Select *p){
150636 Select *pSub, *pPrior;
150637 Expr *pExpr;
150638 Expr *pCount;
150639 sqlite3 *db;
150640 SrcItem *pFrom;
150641 if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
150642 if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
150643 if( p->pWhere ) return 0;
150644 if( p->pHaving ) return 0;
150645 if( p->pGroupBy ) return 0;
@@ -150272,30 +150650,30 @@
150650 if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
150651 assert( ExprUseXList(pExpr) );
150652 if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
150653 if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
150654 if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
150655 pFrom = p->pSrc->a;
150656 if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */
150657 pSub = pFrom->u4.pSubq->pSelect;
150658 if( pSub->pPrior==0 ) return 0; /* Must be a compound */
150659 if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
150660 do{
150661 if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
150662 if( pSub->pWhere ) return 0; /* No WHERE clause */
150663 if( pSub->pLimit ) return 0; /* No LIMIT clause */
150664 if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
150665 assert( pSub->pHaving==0 ); /* Due to the previous */
150666 pSub = pSub->pPrior; /* Repeat over compound */
150667 }while( pSub );
150668
150669 /* If we reach this point then it is OK to perform the transformation */
150670
150671 db = pParse->db;
150672 pCount = pExpr;
150673 pExpr = 0;
150674 pSub = sqlite3SubqueryDetach(db, pFrom);
 
150675 sqlite3SrcListDelete(db, p->pSrc);
150676 p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
150677 while( pSub ){
150678 Expr *pTerm;
150679 pPrior = pSub->pPrior;
@@ -150336,16 +150714,16 @@
150714 static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
150715 int i;
150716 for(i=0; i<pSrc->nSrc; i++){
150717 SrcItem *p1 = &pSrc->a[i];
150718 if( p1==p0 ) continue;
150719 if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
150720 return 1;
150721 }
150722 if( p1->fg.isSubquery
150723 && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0
150724 && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc)
150725 ){
150726 return 1;
150727 }
150728 }
150729 return 0;
@@ -150406,17 +150784,17 @@
150784 while( 1 /*exit-by-break*/ ){
150785 if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
150786 if( i==0 ) break;
150787 i--;
150788 pItem--;
150789 if( pItem->fg.isSubquery ) return 0; /* (1c-i) */
150790 }
150791 return 1;
150792 }
150793
150794 /*
150795 ** Generate byte-code for the SELECT statement given in the p argument.
150796 **
150797 ** The results are returned according to the SelectDest structure.
150798 ** See comments in sqliteInt.h for further information.
150799 **
150800 ** This routine returns the number of errors. If any errors are
@@ -150423,10 +150801,44 @@
150801 ** encountered, then an appropriate error message is left in
150802 ** pParse->zErrMsg.
150803 **
150804 ** This routine does NOT free the Select structure passed in. The
150805 ** calling function needs to do that.
150806 **
150807 ** This is a long function. The following is an outline of the processing
150808 ** steps, with tags referencing various milestones:
150809 **
150810 ** * Resolve names and similar preparation tag-select-0100
150811 ** * Scan of the FROM clause tag-select-0200
150812 ** + OUTER JOIN strength reduction tag-select-0220
150813 ** + Sub-query ORDER BY removal tag-select-0230
150814 ** + Query flattening tag-select-0240
150815 ** * Separate subroutine for compound-SELECT tag-select-0300
150816 ** * WHERE-clause constant propagation tag-select-0330
150817 ** * Count()-of-VIEW optimization tag-select-0350
150818 ** * Scan of the FROM clause again tag-select-0400
150819 ** + Authorize unreferenced tables tag-select-0410
150820 ** + Predicate push-down optimization tag-select-0420
150821 ** + Omit unused subquery columns optimization tag-select-0440
150822 ** + Generate code to implement subqueries tag-select-0480
150823 ** - Co-routines tag-select-0482
150824 ** - Reuse previously computed CTE tag-select-0484
150825 ** - REuse previously computed VIEW tag-select-0486
150826 ** - Materialize a VIEW or CTE tag-select-0488
150827 ** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500
150828 ** * Set up for ORDER BY tag-select-0600
150829 ** * Create output table tag-select-0630
150830 ** * Prepare registers for LIMIT tag-select-0650
150831 ** * Setup for DISTINCT tag-select-0680
150832 ** * Generate code for non-aggregate and non-GROUP BY tag-select-0700
150833 ** * Generate code for aggregate and/or GROUP BY tag-select-0800
150834 ** + GROUP BY queries tag-select-0810
150835 ** + non-GROUP BY queries tag-select-0820
150836 ** - Special case of count() w/o GROUP BY tag-select-0821
150837 ** - General case of non-GROUP BY aggregates tag-select-0822
150838 ** * Sort results, as needed tag-select-0900
150839 ** * Internal self-checks tag-select-1000
150840 */
150841 SQLITE_PRIVATE int sqlite3Select(
150842 Parse *pParse, /* The parser context */
150843 Select *p, /* The SELECT statement being coded. */
150844 SelectDest *pDest /* What to do with the query results */
@@ -150466,10 +150878,11 @@
150878 }
150879 sqlite3ShowSelect(p);
150880 }
150881 #endif
150882
150883 /* tag-select-0100 */
150884 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
150885 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
150886 assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
150887 assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
150888 if( IgnorableDistinct(pDest) ){
@@ -150517,11 +150930,11 @@
150930 if( p->selFlags & SF_UFSrcCheck ){
150931 SrcItem *p0 = &p->pSrc->a[0];
150932 if( sameSrcAlias(p0, p->pSrc) ){
150933 sqlite3ErrorMsg(pParse,
150934 "target object/alias may not appear in FROM clause: %s",
150935 p0->zAlias ? p0->zAlias : p0->pSTab->zName
150936 );
150937 goto select_end;
150938 }
150939
150940 /* Clear the SF_UFSrcCheck flag. The check has already been performed,
@@ -150552,16 +150965,17 @@
150965 memset(&sSort, 0, sizeof(sSort));
150966 sSort.pOrderBy = p->pOrderBy;
150967
150968 /* Try to do various optimizations (flattening subqueries, and strength
150969 ** reduction of join operators) in the FROM clause up into the main query
150970 ** tag-select-0200
150971 */
150972 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
150973 for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
150974 SrcItem *pItem = &pTabList->a[i];
150975 Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0;
150976 Table *pTab = pItem->pSTab;
150977
150978 /* The expander should have already created transient Table objects
150979 ** even for FROM clause elements such as subqueries that do not correspond
150980 ** to a real table */
150981 assert( pTab!=0 );
@@ -150574,10 +150988,11 @@
150988 **
150989 ** If terms of the i-th table are used in the WHERE clause in such a
150990 ** way that the i-th table cannot be the NULL row of a join, then
150991 ** perform the appropriate simplification. This is called
150992 ** "OUTER JOIN strength reduction" in the SQLite documentation.
150993 ** tag-select-0220
150994 */
150995 if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
150996 && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
150997 pItem->fg.jointype & JT_LTORJ)
150998 && OptimizationEnabled(db, SQLITE_SimplifyJoin)
@@ -150644,11 +151059,12 @@
151059 ** flattening in that case.
151060 */
151061 if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
151062 assert( pSub->pGroupBy==0 );
151063
151064 /* tag-select-0230:
151065 ** If a FROM-clause subquery has an ORDER BY clause that is not
151066 ** really doing anything, then delete it now so that it does not
151067 ** interfere with query flattening. See the discussion at
151068 ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
151069 **
151070 ** Beware of these cases where the ORDER BY clause may not be safely
@@ -150710,10 +151126,11 @@
151126 || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0)
151127 ){
151128 continue;
151129 }
151130
151131 /* tag-select-0240 */
151132 if( flattenSubquery(pParse, p, i, isAgg) ){
151133 if( pParse->nErr ) goto select_end;
151134 /* This subquery can be absorbed into its parent. */
151135 i = -1;
151136 }
@@ -150725,11 +151142,11 @@
151142 }
151143 #endif
151144
151145 #ifndef SQLITE_OMIT_COMPOUND_SELECT
151146 /* Handle compound SELECT statements using the separate multiSelect()
151147 ** procedure. tag-select-0300
151148 */
151149 if( p->pPrior ){
151150 rc = multiSelect(pParse, p, pDest);
151151 #if TREETRACE_ENABLED
151152 TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
@@ -150741,13 +151158,13 @@
151158 return rc;
151159 }
151160 #endif
151161
151162 /* Do the WHERE-clause constant propagation optimization if this is
151163 ** a join. No need to spend time on this operation for non-join queries
151164 ** as the equivalent optimization will be handled by query planner in
151165 ** sqlite3WhereBegin(). tag-select-0330
151166 */
151167 if( p->pWhere!=0
151168 && p->pWhere->op==TK_AND
151169 && OptimizationEnabled(db, SQLITE_PropagateConst)
151170 && propagateConstants(pParse, p)
@@ -150760,31 +151177,38 @@
151177 #endif
151178 }else{
151179 TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
151180 }
151181
151182 /* tag-select-0350 */
151183 if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
151184 && countOfViewOptimization(pParse, p)
151185 ){
151186 if( db->mallocFailed ) goto select_end;
151187 pTabList = p->pSrc;
151188 }
151189
151190 /* Loop over all terms in the FROM clause and do two things for each term:
151191 **
151192 ** (1) Authorize unreferenced tables
151193 ** (2) Generate code for all sub-queries
151194 **
151195 ** tag-select-0400
151196 */
151197 for(i=0; i<pTabList->nSrc; i++){
151198 SrcItem *pItem = &pTabList->a[i];
151199 SrcItem *pPrior;
151200 SelectDest dest;
151201 Subquery *pSubq;
151202 Select *pSub;
151203 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
151204 const char *zSavedAuthContext;
151205 #endif
151206
151207 /* Authorized unreferenced tables. tag-select-0410
151208 **
151209 ** Issue SQLITE_READ authorizations with a fake column name for any
151210 ** tables that are referenced but from which no values are extracted.
151211 ** Examples of where these kinds of null SQLITE_READ authorizations
151212 ** would occur:
151213 **
151214 ** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
@@ -150797,21 +151221,32 @@
151221 ** which would be unambiguous. But legacy authorization callbacks might
151222 ** assume the column name is non-NULL and segfault. The use of an empty
151223 ** string for the fake column name seems safer.
151224 */
151225 if( pItem->colUsed==0 && pItem->zName!=0 ){
151226 const char *zDb;
151227 if( pItem->fg.fixedSchema ){
151228 int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema);
151229 zDb = db->aDb[iDb].zDbSName;
151230 }else if( pItem->fg.isSubquery ){
151231 zDb = 0;
151232 }else{
151233 zDb = pItem->u4.zDatabase;
151234 }
151235 sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb);
151236 }
151237
151238 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
151239 /* Generate code for all sub-queries in the FROM clause
151240 */
151241 if( pItem->fg.isSubquery==0 ) continue;
151242 pSubq = pItem->u4.pSubq;
151243 assert( pSubq!=0 );
151244 pSub = pSubq->pSelect;
151245
151246 /* The code for a subquery should only be generated once. */
151247 if( pSubq->addrFillSub!=0 ) continue;
151248
151249 /* Increment Parse.nHeight by the height of the largest expression
151250 ** tree referred to by this, the parent select. The child select
151251 ** may contain expression trees of at most
151252 ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
@@ -150820,10 +151255,11 @@
151255 */
151256 pParse->nHeight += sqlite3SelectExprHeight(p);
151257
151258 /* Make copies of constant WHERE-clause terms in the outer query down
151259 ** inside the subquery. This can help the subquery to run more efficiently.
151260 ** This is the "predicate push-down optimization". tag-select-0420
151261 */
151262 if( OptimizationEnabled(db, SQLITE_PushDown)
151263 && (pItem->fg.isCte==0
151264 || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
151265 && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
@@ -150833,17 +151269,18 @@
151269 TREETRACE(0x4000,pParse,p,
151270 ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
151271 sqlite3TreeViewSelect(0, p, 0);
151272 }
151273 #endif
151274 assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 );
151275 }else{
151276 TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n"));
151277 }
151278
151279 /* Convert unused result columns of the subquery into simple NULL
151280 ** expressions, to avoid unneeded searching and computation.
151281 ** tag-select-0440
151282 */
151283 if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
151284 && disableUnusedSubqueryResultColumns(pItem)
151285 ){
151286 #if TREETRACE_ENABLED
@@ -150857,64 +151294,70 @@
151294 }
151295
151296 zSavedAuthContext = pParse->zAuthContext;
151297 pParse->zAuthContext = pItem->zName;
151298
151299 /* Generate byte-code to implement the subquery tag-select-0480
151300 */
151301 if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
151302 /* Implement a co-routine that will return a single row of the result
151303 ** set on each invocation. tag-select-0482
151304 */
151305 int addrTop = sqlite3VdbeCurrentAddr(v)+1;
151306
151307 pSubq->regReturn = ++pParse->nMem;
151308 sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop);
151309 VdbeComment((v, "%!S", pItem));
151310 pSubq->addrFillSub = addrTop;
151311 sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn);
151312 ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
151313 sqlite3Select(pParse, pSub, &dest);
151314 pItem->pSTab->nRowLogEst = pSub->nSelectRow;
151315 pItem->fg.viaCoroutine = 1;
151316 pSubq->regResult = dest.iSdst;
151317 sqlite3VdbeEndCoroutine(v, pSubq->regReturn);
151318 VdbeComment((v, "end %!S", pItem));
151319 sqlite3VdbeJumpHere(v, addrTop-1);
151320 sqlite3ClearTempRegCache(pParse);
151321 }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
151322 /* This is a CTE for which materialization code has already been
151323 ** generated. Invoke the subroutine to compute the materialization,
151324 ** then make the pItem->iCursor be a copy of the ephemeral table that
151325 ** holds the result of the materialization. tag-select-0484 */
151326 CteUse *pCteUse = pItem->u2.pCteUse;
151327 sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
151328 if( pItem->iCursor!=pCteUse->iCur ){
151329 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
151330 VdbeComment((v, "%!S", pItem));
151331 }
151332 pSub->nSelectRow = pCteUse->nRowEst;
151333 }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
151334 /* This view has already been materialized by a prior entry in
151335 ** this same FROM clause. Reuse it. tag-select-0486 */
151336 Subquery *pPriorSubq;
151337 assert( pPrior->fg.isSubquery );
151338 pPriorSubq = pPrior->u4.pSubq;
151339 assert( pPriorSubq!=0 );
151340 if( pPriorSubq->addrFillSub ){
151341 sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn,
151342 pPriorSubq->addrFillSub);
151343 }
151344 sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
151345 pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow;
151346 }else{
151347 /* Materialize the view. If the view is not correlated, generate a
151348 ** subroutine to do the materialization so that subsequent uses of
151349 ** the same view can reuse the materialization. tag-select-0488 */
151350 int topAddr;
151351 int onceAddr = 0;
151352 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
151353 int addrExplain;
151354 #endif
151355
151356 pSubq->regReturn = ++pParse->nMem;
151357 topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
151358 pSubq->addrFillSub = topAddr+1;
151359 pItem->fg.isMaterialized = 1;
151360 if( pItem->fg.isCorrelated==0 ){
151361 /* If the subquery is not correlated and if we are not inside of
151362 ** a trigger, then we only need to compute the value of the subquery
151363 ** once. */
@@ -150925,21 +151368,21 @@
151368 }
151369 sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
151370
151371 ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
151372 sqlite3Select(pParse, pSub, &dest);
151373 pItem->pSTab->nRowLogEst = pSub->nSelectRow;
151374 if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
151375 sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1);
151376 VdbeComment((v, "end %!S", pItem));
151377 sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
151378 sqlite3VdbeJumpHere(v, topAddr);
151379 sqlite3ClearTempRegCache(pParse);
151380 if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
151381 CteUse *pCteUse = pItem->u2.pCteUse;
151382 pCteUse->addrM9e = pSubq->addrFillSub;
151383 pCteUse->regRtn = pSubq->regReturn;
151384 pCteUse->iCur = pItem->iCursor;
151385 pCteUse->nRowEst = pSub->nSelectRow;
151386 }
151387 }
151388 if( db->mallocFailed ) goto select_end;
@@ -150961,11 +151404,13 @@
151404 TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
151405 sqlite3TreeViewSelect(0, p, 0);
151406 }
151407 #endif
151408
151409 /* tag-select-0500
151410 **
151411 ** If the query is DISTINCT with an ORDER BY but is not an aggregate, and
151412 ** if the select-list is the same as the ORDER BY list, then this query
151413 ** can be rewritten as a GROUP BY. In other words, this:
151414 **
151415 ** SELECT DISTINCT xyz FROM ... ORDER BY xyz
151416 **
@@ -151011,11 +151456,11 @@
151456 ** do the sorting. But this sorting ephemeral index might end up
151457 ** being unused if the data can be extracted in pre-sorted order.
151458 ** If that is the case, then the OP_OpenEphemeral instruction will be
151459 ** changed to an OP_Noop once we figure out that the sorting index is
151460 ** not needed. The sSort.addrSortIndex variable is used to facilitate
151461 ** that change. tag-select-0600
151462 */
151463 if( sSort.pOrderBy ){
151464 KeyInfo *pKeyInfo;
151465 pKeyInfo = sqlite3KeyInfoFromExprList(
151466 pParse, sSort.pOrderBy, 0, pEList->nExpr);
@@ -151028,10 +151473,11 @@
151473 }else{
151474 sSort.addrSortIndex = -1;
151475 }
151476
151477 /* If the output is destined for a temporary table, open that table.
151478 ** tag-select-0630
151479 */
151480 if( pDest->eDest==SRT_EphemTab ){
151481 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
151482 if( p->selFlags & SF_NestedFrom ){
151483 /* Delete or NULL-out result columns that will never be used */
@@ -151045,11 +151491,11 @@
151491 if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
151492 }
151493 }
151494 }
151495
151496 /* Set the limiter. tag-select-0650
151497 */
151498 iEnd = sqlite3VdbeMakeLabel(pParse);
151499 if( (p->selFlags & SF_FixedLimit)==0 ){
151500 p->nSelectRow = 320; /* 4 billion rows */
151501 }
@@ -151057,11 +151503,11 @@
151503 if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
151504 sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
151505 sSort.sortFlags |= SORTFLAG_UseSorter;
151506 }
151507
151508 /* Open an ephemeral index to use for the distinct set. tag-select-0680
151509 */
151510 if( p->selFlags & SF_Distinct ){
151511 sDistinct.tabTnct = pParse->nTab++;
151512 sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
151513 sDistinct.tabTnct, 0, 0,
@@ -151072,11 +151518,11 @@
151518 }else{
151519 sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
151520 }
151521
151522 if( !isAgg && pGroupBy==0 ){
151523 /* No aggregate functions and no GROUP BY clause. tag-select-0700 */
151524 u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
151525 | (p->selFlags & SF_FixedLimit);
151526 #ifndef SQLITE_OMIT_WINDOWFUNC
151527 Window *pWin = p->pWin; /* Main window object (or NULL) */
151528 if( pWin ){
@@ -151145,12 +151591,12 @@
151591 */
151592 TREETRACE(0x2,pParse,p,("WhereEnd\n"));
151593 sqlite3WhereEnd(pWInfo);
151594 }
151595 }else{
151596 /* This case is for when there exist aggregate functions or a GROUP BY
151597 ** clause or both. tag-select-0800 */
151598 NameContext sNC; /* Name context for processing aggregate information */
151599 int iAMem; /* First Mem address for storing current GROUP BY */
151600 int iBMem; /* First Mem address for previous GROUP BY */
151601 int iUseFlag; /* Mem address holding flag indicating that at least
151602 ** one row of the input to the aggregator has been
@@ -151265,11 +151711,11 @@
151711 }
151712 #endif
151713
151714
151715 /* Processing for aggregates with GROUP BY is very different and
151716 ** much more complex than aggregates without a GROUP BY. tag-select-0810
151717 */
151718 if( pGroupBy ){
151719 KeyInfo *pKeyInfo; /* Keying information for the group by clause */
151720 int addr1; /* A-vs-B comparison jump */
151721 int addrOutputRow; /* Start of subroutine that outputs a result row */
@@ -151562,13 +152008,16 @@
152008 struct AggInfo_func *pF = &pAggInfo->aFunc[0];
152009 fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
152010 }
152011 } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
152012 else {
152013 /* Aggregate functions without GROUP BY. tag-select-0820 */
152014 Table *pTab;
152015 if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
152016 /* tag-select-0821
152017 **
152018 ** If isSimpleCount() returns a pointer to a Table structure, then
152019 ** the SQL statement is of the form:
152020 **
152021 ** SELECT count(*) FROM <tbl>
152022 **
152023 ** where the Table structure returned represents table <tbl>.
@@ -151623,10 +152072,12 @@
152072 assignAggregateRegisters(pParse, pAggInfo);
152073 sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
152074 sqlite3VdbeAddOp1(v, OP_Close, iCsr);
152075 explainSimpleCount(pParse, pTab, pBest);
152076 }else{
152077 /* The general case of an aggregate query without GROUP BY
152078 ** tag-select-0822 */
152079 int regAcc = 0; /* "populate accumulators" flag */
152080 ExprList *pDistinct = 0;
152081 u16 distFlag = 0;
152082 int eDist;
152083
@@ -151711,11 +152162,11 @@
152162 if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
152163 explainTempTable(pParse, "DISTINCT");
152164 }
152165
152166 /* If there is an ORDER BY clause, then we need to sort the results
152167 ** and send them to the callback one by one. tag-select-0900
152168 */
152169 if( sSort.pOrderBy ){
152170 assert( p->pEList==pEList );
152171 generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
152172 }
@@ -151734,10 +152185,11 @@
152185 select_end:
152186 assert( db->mallocFailed==0 || db->mallocFailed==1 );
152187 assert( db->mallocFailed==0 || pParse->nErr!=0 );
152188 sqlite3ExprListDelete(db, pMinMaxOrderBy);
152189 #ifdef SQLITE_DEBUG
152190 /* Internal self-checks. tag-select-1000 */
152191 if( pAggInfo && !db->mallocFailed ){
152192 #if TREETRACE_ENABLED
152193 if( sqlite3TreeTrace & 0x20 ){
152194 TREETRACE(0x20,pParse,p,("Finished with AggInfo\n"));
152195 printAggInfo(pAggInfo);
@@ -152123,12 +152575,14 @@
152575 **
152576 ** To maintain backwards compatibility, ignore the database
152577 ** name on pTableName if we are reparsing out of the schema table
152578 */
152579 if( db->init.busy && iDb!=1 ){
152580 assert( pTableName->a[0].fg.fixedSchema==0 );
152581 assert( pTableName->a[0].fg.isSubquery==0 );
152582 sqlite3DbFree(db, pTableName->a[0].u4.zDatabase);
152583 pTableName->a[0].u4.zDatabase = 0;
152584 }
152585
152586 /* If the trigger name was unqualified, and the table is a temp table,
152587 ** then set iDb to 1 to create the trigger in the temporary database.
152588 ** If sqlite3SrcListLookup() returns 0, indicating the table does not
@@ -152602,11 +153056,12 @@
153056 if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
153057 goto drop_trigger_cleanup;
153058 }
153059
153060 assert( pName->nSrc==1 );
153061 assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 );
153062 zDb = pName->a[0].u4.zDatabase;
153063 zName = pName->a[0].zName;
153064 assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
153065 for(i=OMIT_TEMPDB; i<db->nDb; i++){
153066 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
153067 if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
@@ -152839,11 +153294,13 @@
153294 assert( zName || pSrc==0 );
153295 if( pSrc ){
153296 Schema *pSchema = pStep->pTrig->pSchema;
153297 pSrc->a[0].zName = zName;
153298 if( pSchema!=db->aDb[1].pSchema ){
153299 assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 );
153300 pSrc->a[0].u4.pSchema = pSchema;
153301 pSrc->a[0].fg.fixedSchema = 1;
153302 }
153303 if( pStep->pFrom ){
153304 SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
153305 if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
153306 Select *pSubquery;
@@ -152952,11 +153409,11 @@
153409 SrcList *pSrc;
153410 assert( pSelect!=0 );
153411 pSrc = pSelect->pSrc;
153412 assert( pSrc!=0 );
153413 for(i=0; i<pSrc->nSrc; i++){
153414 if( pSrc->a[i].pSTab==pWalker->u.pTab ){
153415 testcase( pSelect->selFlags & SF_Correlated );
153416 pSelect->selFlags |= SF_Correlated;
153417 pWalker->eCode = 1;
153418 break;
153419 }
@@ -153023,11 +153480,11 @@
153480 memset(&sSelect, 0, sizeof(sSelect));
153481 memset(&sFrom, 0, sizeof(sFrom));
153482 sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
153483 sSelect.pSrc = &sFrom;
153484 sFrom.nSrc = 1;
153485 sFrom.a[0].pSTab = pTab;
153486 sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */
153487 sFrom.a[0].iCursor = -1;
153488 sqlite3SelectPrep(pParse, &sSelect, 0);
153489 if( pParse->nErr==0 ){
153490 assert( db->mallocFailed==0 );
@@ -153734,11 +154191,11 @@
154191 ExprList *pList = 0;
154192 ExprList *pGrp = 0;
154193 Expr *pLimit2 = 0;
154194 ExprList *pOrderBy2 = 0;
154195 sqlite3 *db = pParse->db;
154196 Table *pTab = pTabList->a[0].pSTab;
154197 SrcList *pSrc;
154198 Expr *pWhere2;
154199 int eDest;
154200
154201 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -153758,12 +154215,12 @@
154215
154216 assert( pTabList->nSrc>1 );
154217 if( pSrc ){
154218 assert( pSrc->a[0].fg.notCte );
154219 pSrc->a[0].iCursor = -1;
154220 pSrc->a[0].pSTab->nTabRef--;
154221 pSrc->a[0].pSTab = 0;
154222 }
154223 if( pPk ){
154224 for(i=0; i<pPk->nKeyCol; i++){
154225 Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
154226 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
@@ -155007,11 +155464,11 @@
155464 NameContext sNC; /* Context for resolving symbolic names */
155465 Expr sCol[2]; /* Index column converted into an Expr */
155466 int nClause = 0; /* Counter of ON CONFLICT clauses */
155467
155468 assert( pTabList->nSrc==1 );
155469 assert( pTabList->a[0].pSTab!=0 );
155470 assert( pUpsert!=0 );
155471 assert( pUpsert->pUpsertTarget!=0 );
155472
155473 /* Resolve all symbolic names in the conflict-target clause, which
155474 ** includes both the list of columns and the optional partial-index
@@ -155026,11 +155483,11 @@
155483 if( rc ) return rc;
155484 rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
155485 if( rc ) return rc;
155486
155487 /* Check to see if the conflict target matches the rowid. */
155488 pTab = pTabList->a[0].pSTab;
155489 pTarget = pUpsert->pUpsertTarget;
155490 iCursor = pTabList->a[0].iCursor;
155491 if( HasRowid(pTab)
155492 && pTarget->nExpr==1
155493 && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
@@ -155397,10 +155854,13 @@
155854 int nRes; /* Bytes of reserved space at the end of each page */
155855 int nDb; /* Number of attached databases */
155856 const char *zDbMain; /* Schema name of database to vacuum */
155857 const char *zOut; /* Name of output file */
155858 u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
155859 u64 iRandom; /* Random value used for zDbVacuum[] */
155860 char zDbVacuum[42]; /* Name of the ATTACH-ed database used for vacuum */
155861
155862
155863 if( !db->autoCommit ){
155864 sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
155865 return SQLITE_ERROR; /* IMP: R-12218-18073 */
155866 }
@@ -155437,31 +155897,33 @@
155897
155898 zDbMain = db->aDb[iDb].zDbSName;
155899 pMain = db->aDb[iDb].pBt;
155900 isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
155901
155902 /* Attach the temporary database as 'vacuum_XXXXXX'. The synchronous pragma
155903 ** can be set to 'off' for this file, as it is not recovered if a crash
155904 ** occurs anyway. The integrity of the database is maintained by a
155905 ** (possibly synchronous) transaction opened on the main database before
155906 ** sqlite3BtreeCopyFile() is called.
155907 **
155908 ** An optimization would be to use a non-journaled pager.
155909 ** (Later:) I tried setting "PRAGMA vacuum_XXXXXX.journal_mode=OFF" but
155910 ** that actually made the VACUUM run slower. Very little journalling
155911 ** actually occurs when doing a vacuum since the vacuum_db is initially
155912 ** empty. Only the journal header is written. Apparently it takes more
155913 ** time to parse and run the PRAGMA to turn journalling off than it does
155914 ** to write the journal header file.
155915 */
155916 sqlite3_randomness(sizeof(iRandom),&iRandom);
155917 sqlite3_snprintf(sizeof(zDbVacuum), zDbVacuum, "vacuum_%016llx", iRandom);
155918 nDb = db->nDb;
155919 rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS %s", zOut, zDbVacuum);
155920 db->openFlags = saved_openFlags;
155921 if( rc!=SQLITE_OK ) goto end_of_vacuum;
155922 assert( (db->nDb-1)==nDb );
155923 pDb = &db->aDb[nDb];
155924 assert( strcmp(pDb->zDbSName,zDbVacuum)==0 );
155925 pTemp = pDb->pBt;
155926 if( pOut ){
155927 sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
155928 i64 sz = 0;
155929 if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
@@ -155534,15 +155996,15 @@
155996 /* Loop through the tables in the main database. For each, do
155997 ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
155998 ** the contents to the temporary database.
155999 */
156000 rc = execSqlF(db, pzErrMsg,
156001 "SELECT'INSERT INTO %s.'||quote(name)"
156002 "||' SELECT*FROM\"%w\".'||quote(name)"
156003 "FROM %s.sqlite_schema "
156004 "WHERE type='table'AND coalesce(rootpage,1)>0",
156005 zDbVacuum, zDbMain, zDbVacuum
156006 );
156007 assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
156008 db->mDbFlags &= ~DBFLAG_Vacuum;
156009 if( rc!=SQLITE_OK ) goto end_of_vacuum;
156010
@@ -155550,15 +156012,15 @@
156012 ** over to the temporary database. None of these objects has any
156013 ** associated storage, so all we have to do is copy their entries
156014 ** from the schema table.
156015 */
156016 rc = execSqlF(db, pzErrMsg,
156017 "INSERT INTO %s.sqlite_schema"
156018 " SELECT*FROM \"%w\".sqlite_schema"
156019 " WHERE type IN('view','trigger')"
156020 " OR(type='table'AND rootpage=0)",
156021 zDbVacuum, zDbMain
156022 );
156023 if( rc ) goto end_of_vacuum;
156024
156025 /* At this point, there is a write transaction open on both the
156026 ** vacuum database and the main database. Assuming no error occurs,
@@ -157198,10 +157660,11 @@
157660 } btree;
157661 struct { /* Information for virtual tables */
157662 int idxNum; /* Index number */
157663 u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
157664 u32 bOmitOffset : 1; /* True to let virtual table handle offset */
157665 u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */
157666 i8 isOrdered; /* True if satisfies ORDER BY */
157667 u16 omitMask; /* Terms that may be omitted */
157668 char *idxStr; /* Index identifier string */
157669 u32 mHandleIn; /* Terms to handle as IN(...) instead of == */
157670 } vtab;
@@ -157832,11 +158295,11 @@
158295 Index *pIdx;
158296
158297 assert( pLoop->u.btree.pIndex!=0 );
158298 pIdx = pLoop->u.btree.pIndex;
158299 assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
158300 if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){
158301 if( isSearch ){
158302 zFmt = "PRIMARY KEY";
158303 }
158304 }else if( flags & WHERE_PARTIALIDX ){
158305 zFmt = "AUTOMATIC PARTIAL COVERING INDEX";
@@ -157875,11 +158338,13 @@
158338 }
158339 sqlite3_str_appendf(&str, "%c?)", cRangeOp);
158340 }
158341 #ifndef SQLITE_OMIT_VIRTUALTABLE
158342 else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
158343 sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX ");
158344 sqlite3_str_appendf(&str,
158345 pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s",
158346 pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
158347 }
158348 #endif
158349 if( pItem->fg.jointype & JT_LEFT ){
158350 sqlite3_str_appendf(&str, " LEFT-JOIN");
@@ -157929,11 +158394,11 @@
158394 sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
158395 str.printfFlags = SQLITE_PRINTF_INTERNAL;
158396 sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
158397 pLoop = pLevel->pWLoop;
158398 if( pLoop->wsFlags & WHERE_IPK ){
158399 const Table *pTab = pItem->pSTab;
158400 if( pTab->iPKey>=0 ){
158401 sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
158402 }else{
158403 sqlite3_str_appendf(&str, "rowid=?");
158404 }
@@ -157992,11 +158457,13 @@
158457 }
158458 if( wsFlags & WHERE_INDEXED ){
158459 sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
158460 }
158461 }else{
158462 int addr;
158463 assert( pSrclist->a[pLvl->iFrom].fg.isSubquery );
158464 addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub;
158465 VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
158466 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
158467 assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
158468 sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
158469 }
@@ -159129,11 +159596,12 @@
159596 pLoop = pLevel->pWLoop;
159597 pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
159598 iCur = pTabItem->iCursor;
159599 pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
159600 bRev = (pWInfo->revMask>>iLevel)&1;
159601 VdbeModuleComment((v, "Begin WHERE-loop%d: %s",
159602 iLevel, pTabItem->pSTab->zName));
159603 #if WHERETRACE_ENABLED /* 0x4001 */
159604 if( sqlite3WhereTrace & 0x1 ){
159605 sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
159606 iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
159607 if( sqlite3WhereTrace & 0x1000 ){
@@ -159184,15 +159652,19 @@
159652 }
159653 addrHalt = pWInfo->a[j].addrBrk;
159654
159655 /* Special case of a FROM clause subquery implemented as a co-routine */
159656 if( pTabItem->fg.viaCoroutine ){
159657 int regYield;
159658 Subquery *pSubq;
159659 assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 );
159660 pSubq = pTabItem->u4.pSubq;
159661 regYield = pSubq->regReturn;
159662 sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
159663 pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
159664 VdbeCoverage(v);
159665 VdbeComment((v, "next row of %s", pTabItem->pSTab->zName));
159666 pLevel->op = OP_Goto;
159667 }else
159668
159669 #ifndef SQLITE_OMIT_VIRTUALTABLE
159670 if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
@@ -159917,11 +160389,11 @@
160389 int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */
160390 int iRetInit; /* Address of regReturn init */
160391 int untestedTerms = 0; /* Some terms not completely tested */
160392 int ii; /* Loop counter */
160393 Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
160394 Table *pTab = pTabItem->pSTab;
160395
160396 pTerm = pLoop->aLTerm[0];
160397 assert( pTerm!=0 );
160398 assert( pTerm->eOperator & WO_OR );
160399 assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
@@ -160376,11 +160848,11 @@
160848 /* pTab is the right-hand table of the RIGHT JOIN. Generate code that
160849 ** will record that the current row of that table has been matched at
160850 ** least once. This is accomplished by storing the PK for the row in
160851 ** both the iMatch index and the regBloom Bloom filter.
160852 */
160853 pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab;
160854 if( HasRowid(pTab) ){
160855 r = sqlite3GetTempRange(pParse, 2);
160856 sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
160857 nPk = 1;
160858 }else{
@@ -160483,23 +160955,27 @@
160955 SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
160956 SrcList sFrom;
160957 Bitmask mAll = 0;
160958 int k;
160959
160960 ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
160961 sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
160962 pRJ->regReturn);
160963 for(k=0; k<iLevel; k++){
160964 int iIdxCur;
160965 SrcItem *pRight;
160966 assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom );
160967 pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom];
160968 mAll |= pWInfo->a[k].pWLoop->maskSelf;
160969 if( pRight->fg.viaCoroutine ){
160970 Subquery *pSubq;
160971 assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 );
160972 pSubq = pRight->u4.pSubq;
160973 assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 );
160974 sqlite3VdbeAddOp3(
160975 v, OP_Null, 0, pSubq->regResult,
160976 pSubq->regResult + pSubq->pSelect->pEList->nExpr-1
160977 );
160978 }
160979 sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
160980 iIdxCur = pWInfo->a[k].iIdxCur;
160981 if( iIdxCur ){
@@ -160533,11 +161009,11 @@
161009 int iCur = pLevel->iTabCur;
161010 int r = ++pParse->nMem;
161011 int nPk;
161012 int jmp;
161013 int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
161014 Table *pTab = pTabItem->pSTab;
161015 if( HasRowid(pTab) ){
161016 sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
161017 nPk = 1;
161018 }else{
161019 int iPk;
@@ -160785,15 +161261,24 @@
161261 assert( !ExprHasProperty(pRight, EP_IntValue) );
161262 z = (u8*)pRight->u.zToken;
161263 }
161264 if( z ){
161265
161266 /* Count the number of prefix characters prior to the first wildcard.
161267 ** If the underlying database has a UTF16LE encoding, then only consider
161268 ** ASCII characters. Note that the encoding of z[] is UTF8 - we are
161269 ** dealing with only UTF8 here in this code, but the database engine
161270 ** itself might be processing content using a different encoding. */
161271 cnt = 0;
161272 while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
161273 cnt++;
161274 if( c==wc[3] && z[cnt]!=0 ){
161275 cnt++;
161276 }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){
161277 cnt--;
161278 break;
161279 }
161280 }
161281
161282 /* The optimization is possible only if (1) the pattern does not begin
161283 ** with a wildcard and if (2) the non-wildcard prefix does not end with
161284 ** an (illegal 0xff) character, or (3) the pattern does not consist of
@@ -160804,11 +161289,11 @@
161289 ** removed. */
161290 if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
161291 Expr *pPrefix;
161292
161293 /* A "complete" match if the pattern ends with "*" or "%" */
161294 *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE;
161295
161296 /* Get the pattern prefix. Remove all escapes from the prefix. */
161297 pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
161298 if( pPrefix ){
161299 int iFrom, iTo;
@@ -161523,11 +162008,13 @@
162008 mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere);
162009 mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving);
162010 if( ALWAYS(pSrc!=0) ){
162011 int i;
162012 for(i=0; i<pSrc->nSrc; i++){
162013 if( pSrc->a[i].fg.isSubquery ){
162014 mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect);
162015 }
162016 if( pSrc->a[i].fg.isUsing==0 ){
162017 mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
162018 }
162019 if( pSrc->a[i].fg.isTabFunc ){
162020 mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
@@ -161561,11 +162048,11 @@
162048 Index *pIdx;
162049 int i;
162050 int iCur;
162051 do{
162052 iCur = pFrom->a[j].iCursor;
162053 for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
162054 if( pIdx->aColExpr==0 ) continue;
162055 for(i=0; i<pIdx->nKeyCol; i++){
162056 if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
162057 assert( pIdx->bHasExpr );
162058 if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
@@ -161605,11 +162092,11 @@
162092 return 1;
162093 }
162094
162095 for(i=0; i<pFrom->nSrc; i++){
162096 Index *pIdx;
162097 for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){
162098 if( pIdx->aColExpr ){
162099 return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
162100 }
162101 }
162102 }
@@ -162193,11 +162680,11 @@
162680 */
162681 SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
162682 assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
162683 if( p->pGroupBy==0
162684 && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
162685 && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */
162686 ){
162687 ExprList *pOrderBy = p->pOrderBy;
162688 int iCsr = p->pSrc->a[0].iCursor;
162689 int ii;
162690
@@ -162414,11 +162901,11 @@
162901 int j, k;
162902 ExprList *pArgs;
162903 Expr *pColRef;
162904 Expr *pTerm;
162905 if( pItem->fg.isTabFunc==0 ) return;
162906 pTab = pItem->pSTab;
162907 assert( pTab!=0 );
162908 pArgs = pItem->u1.pFuncArg;
162909 if( pArgs==0 ) return;
162910 for(j=k=0; j<pArgs->nExpr; j++){
162911 Expr *pRhs;
@@ -163098,11 +163585,11 @@
163585 /* If there is more than one table or sub-select in the FROM clause of
163586 ** this query, then it will not be possible to show that the DISTINCT
163587 ** clause is redundant. */
163588 if( pTabList->nSrc!=1 ) return 0;
163589 iBase = pTabList->a[0].iCursor;
163590 pTab = pTabList->a[0].pSTab;
163591
163592 /* If any of the expressions is an IPK column on table iBase, then return
163593 ** true. Note: The (p->iTable==iBase) part of this test may be false if the
163594 ** current SELECT is a correlated sub-query.
163595 */
@@ -163362,14 +163849,14 @@
163849 }
163850 if( (pTerm->prereqRight & notReady)!=0 ) return 0;
163851 assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
163852 leftCol = pTerm->u.x.leftColumn;
163853 if( leftCol<0 ) return 0;
163854 aff = pSrc->pSTab->aCol[leftCol].affinity;
163855 if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
163856 testcase( pTerm->pExpr->op==TK_IS );
163857 return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol);
163858 }
163859 #endif
163860
163861
163862 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -163473,11 +163960,11 @@
163960 /* Count the number of columns that will be added to the index
163961 ** and used to match WHERE clause constraints */
163962 nKeyCol = 0;
163963 pTabList = pWC->pWInfo->pTabList;
163964 pSrc = &pTabList->a[pLevel->iFrom];
163965 pTable = pSrc->pSTab;
163966 pWCEnd = &pWC->a[pWC->nTerm];
163967 pLoop = pLevel->pWLoop;
163968 idxCols = 0;
163969 for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
163970 Expr *pExpr = pTerm->pExpr;
@@ -163615,16 +164102,21 @@
164102 }
164103
164104 /* Fill the automatic index with content */
164105 assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
164106 if( pSrc->fg.viaCoroutine ){
164107 int regYield;
164108 Subquery *pSubq;
164109 assert( pSrc->fg.isSubquery );
164110 pSubq = pSrc->u4.pSubq;
164111 assert( pSubq!=0 );
164112 regYield = pSubq->regReturn;
164113 addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
164114 sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub);
164115 addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
164116 VdbeCoverage(v);
164117 VdbeComment((v, "next row of %s", pSrc->pSTab->zName));
164118 }else{
164119 addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
164120 }
164121 if( pPartial ){
164122 iContinue = sqlite3VdbeMakeLabel(pParse);
@@ -163642,15 +164134,16 @@
164134 sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v));
164135 sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
164136 sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
164137 if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
164138 if( pSrc->fg.viaCoroutine ){
164139 assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 );
164140 sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
164141 testcase( pParse->db->mallocFailed );
164142 assert( pLevel->iIdxCur>0 );
164143 translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
164144 pSrc->u4.pSubq->regResult, pLevel->iIdxCur);
164145 sqlite3VdbeGoto(v, addrTop);
164146 pSrc->fg.viaCoroutine = 0;
164147 }else{
164148 sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
164149 sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -163737,11 +164230,11 @@
164230 */
164231 pTabList = pWInfo->pTabList;
164232 iSrc = pLevel->iFrom;
164233 pItem = &pTabList->a[iSrc];
164234 assert( pItem!=0 );
164235 pTab = pItem->pSTab;
164236 assert( pTab!=0 );
164237 sz = sqlite3LogEstToInt(pTab->nRowLogEst);
164238 if( sz<10000 ){
164239 sz = 10000;
164240 }else if( sz>10000000 ){
@@ -163768,11 +164261,11 @@
164261 Index *pIdx = pLoop->u.btree.pIndex;
164262 int n = pLoop->u.btree.nEq;
164263 int r1 = sqlite3GetTempRange(pParse, n);
164264 int jj;
164265 for(jj=0; jj<n; jj++){
164266 assert( pIdx->pTable==pItem->pSTab );
164267 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
164268 }
164269 sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
164270 sqlite3ReleaseTempRange(pParse, r1, n);
164271 }
@@ -163849,11 +164342,11 @@
164342 int eDistinct = 0;
164343 ExprList *pOrderBy = pWInfo->pOrderBy;
164344 WhereClause *p;
164345
164346 assert( pSrc!=0 );
164347 pTab = pSrc->pSTab;
164348 assert( pTab!=0 );
164349 assert( IsVirtual(pTab) );
164350
164351 /* Find all WHERE clause constraints referring to this virtual table.
164352 ** Mark each term with the TERM_OK flag. Set nTerm to the number of
@@ -164857,11 +165350,11 @@
165350 SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
165351 if( pWC ){
165352 WhereInfo *pWInfo = pWC->pWInfo;
165353 int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
165354 SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
165355 Table *pTab = pItem->pSTab;
165356 Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
165357 sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
165358 p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
165359 sqlite3DebugPrintf(" %12s",
165360 pItem->zAlias ? pItem->zAlias : pTab->zName);
@@ -165845,19 +166338,19 @@
166338 ** 1. The cost of doing one search-by-key to find the first matching
166339 ** entry
166340 ** 2. Stepping forward in the index pNew->nOut times to find all
166341 ** additional matching entries.
166342 */
166343 assert( pSrc->pSTab->szTabRow>0 );
166344 if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
166345 /* The pProbe->szIdxRow is low for an IPK table since the interior
166346 ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
166347 ** But the leaf pages are full-size, so pProbe->szIdxRow would badly
166348 ** under-estimate the scanning cost. */
166349 rCostIdx = pNew->nOut + 16;
166350 }else{
166351 rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow;
166352 }
166353 rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx);
166354
166355 /* Estimate the cost of running the loop. If all data is coming
166356 ** from the index, then this is just the cost of doing the index
@@ -166318,13 +166811,13 @@
166811
166812 pNew = pBuilder->pNew;
166813 pWInfo = pBuilder->pWInfo;
166814 pTabList = pWInfo->pTabList;
166815 pSrc = pTabList->a + pNew->iTab;
166816 pTab = pSrc->pSTab;
166817 pWC = pBuilder->pWC;
166818 assert( !IsVirtual(pSrc->pSTab) );
166819
166820 if( pSrc->fg.isIndexedBy ){
166821 assert( pSrc->fg.isCte==0 );
166822 /* An INDEXED BY clause specifies a particular index to use */
166823 pProbe = pSrc->u2.pIBIndex;
@@ -166345,11 +166838,11 @@
166838 sPk.pTable = pTab;
166839 sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
166840 sPk.idxType = SQLITE_IDXTYPE_IPK;
166841 aiRowEstPk[0] = pTab->nRowLogEst;
166842 aiRowEstPk[1] = 0;
166843 pFirst = pSrc->pSTab->pIndex;
166844 if( pSrc->fg.notIndexed==0 ){
166845 /* The real indices of the table are only considered if the
166846 ** NOT INDEXED qualifier is omitted from the FROM clause */
166847 sPk.pNext = pFirst;
166848 }
@@ -166435,10 +166928,11 @@
166928 pNew->iSortIdx = 0;
166929 pNew->rSetup = 0;
166930 pNew->prereq = mPrereq;
166931 pNew->nOut = rSize;
166932 pNew->u.btree.pIndex = pProbe;
166933 pNew->u.btree.pOrderBy = 0;
166934 b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
166935
166936 /* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
166937 assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
166938 if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
@@ -166464,13 +166958,13 @@
166958 #else
166959 pNew->rRun = rSize + 16;
166960 #endif
166961 ApplyCostMultiplier(pNew->rRun, pTab->costMult);
166962 whereLoopOutputAdjust(pWC, pNew, rSize);
166963 if( pSrc->fg.isSubquery ){
166964 if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE;
166965 pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy;
166966 }
166967 rc = whereLoopInsert(pBuilder, pNew);
166968 pNew->nOut = rSize;
166969 if( rc ) break;
166970 }else{
@@ -166692,11 +167186,11 @@
167186 pIdxInfo->estimatedRows = 25;
167187 pIdxInfo->idxFlags = 0;
167188 pHidden->mHandleIn = 0;
167189
167190 /* Invoke the virtual table xBestIndex() method */
167191 rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo);
167192 if( rc ){
167193 if( rc==SQLITE_CONSTRAINT ){
167194 /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
167195 ** that the particular combination of parameters provided is unusable.
167196 ** Make no entries in the loop table.
@@ -166722,11 +167216,11 @@
167216 || j<0
167217 || (pTerm = termFromWhereClause(pWC, j))==0
167218 || pNew->aLTerm[iTerm]!=0
167219 || pIdxCons->usable==0
167220 ){
167221 sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
167222 freeIdxStr(pIdxInfo);
167223 return SQLITE_ERROR;
167224 }
167225 testcase( iTerm==nConstraint-1 );
167226 testcase( j==0 );
@@ -166785,11 +167279,11 @@
167279 pNew->nLTerm = mxTerm+1;
167280 for(i=0; i<=mxTerm; i++){
167281 if( pNew->aLTerm[i]==0 ){
167282 /* The non-zero argvIdx values must be contiguous. Raise an
167283 ** error if they are not */
167284 sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName);
167285 freeIdxStr(pIdxInfo);
167286 return SQLITE_ERROR;
167287 }
167288 }
167289 assert( pNew->nLTerm<=pNew->nLSlot );
@@ -166797,10 +167291,11 @@
167291 pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
167292 pIdxInfo->needToFreeIdxStr = 0;
167293 pNew->u.vtab.idxStr = pIdxInfo->idxStr;
167294 pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
167295 pIdxInfo->nOrderBy : 0);
167296 pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0;
167297 pNew->rSetup = 0;
167298 pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
167299 pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
167300
167301 /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
@@ -166987,11 +167482,11 @@
167482 pWInfo = pBuilder->pWInfo;
167483 pParse = pWInfo->pParse;
167484 pWC = pBuilder->pWC;
167485 pNew = pBuilder->pNew;
167486 pSrc = &pWInfo->pTabList->a[pNew->iTab];
167487 assert( IsVirtual(pSrc->pSTab) );
167488 p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
167489 if( p==0 ) return SQLITE_NOMEM_BKPT;
167490 pNew->rSetup = 0;
167491 pNew->wsFlags = WHERE_VIRTUALTABLE;
167492 pNew->nLTerm = 0;
@@ -167001,11 +167496,11 @@
167496 freeIndexInfo(pParse->db, p);
167497 return SQLITE_NOMEM_BKPT;
167498 }
167499
167500 /* First call xBestIndex() with all constraints usable. */
167501 WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName));
167502 WHERETRACE(0x800, (" VirtualOne: all usable\n"));
167503 rc = whereLoopAddVirtualOne(
167504 pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
167505 );
167506 if( bRetry ){
@@ -167083,11 +167578,11 @@
167578 pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
167579 }
167580 }
167581
167582 freeIndexInfo(pParse->db, p);
167583 WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc));
167584 return rc;
167585 }
167586 #endif /* SQLITE_OMIT_VIRTUALTABLE */
167587
167588 /*
@@ -167155,11 +167650,11 @@
167650 if( sqlite3WhereTrace & 0x20000 ){
167651 sqlite3WhereClausePrint(sSubBuild.pWC);
167652 }
167653 #endif
167654 #ifndef SQLITE_OMIT_VIRTUALTABLE
167655 if( IsVirtual(pItem->pSTab) ){
167656 rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
167657 }else
167658 #endif
167659 {
167660 rc = whereLoopAddBtree(&sSubBuild, mPrereq);
@@ -167269,11 +167764,11 @@
167764 bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0;
167765 }else if( !hasRightJoin ){
167766 mPrereq = 0;
167767 }
167768 #ifndef SQLITE_OMIT_VIRTUALTABLE
167769 if( IsVirtual(pItem->pSTab) ){
167770 SrcItem *p;
167771 for(p=&pItem[1]; p<pEnd; p++){
167772 if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
167773 mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
167774 }
@@ -167905,11 +168400,11 @@
168400 rDelta = 15*(nDep-3);
168401 #ifdef WHERETRACE_ENABLED /* 0x4 */
168402 if( sqlite3WhereTrace&0x4 ){
168403 SrcItem *pItem = pWInfo->pTabList->a + iLoop;
168404 sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n",
168405 pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName,
168406 nDep, rDelta);
168407 }
168408 #endif
168409 if( pWInfo->nOutStarDelta==0 ){
168410 for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
@@ -168455,11 +168950,11 @@
168950
168951 pWInfo = pBuilder->pWInfo;
168952 if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
168953 assert( pWInfo->pTabList->nSrc>=1 );
168954 pItem = pWInfo->pTabList->a;
168955 pTab = pItem->pSTab;
168956 if( IsVirtual(pTab) ) return 0;
168957 if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
168958 testcase( pItem->fg.isIndexedBy );
168959 testcase( pItem->fg.notIndexed );
168960 return 0;
@@ -168718,11 +169213,11 @@
169213 assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
169214 for(i=0; i<pWInfo->nLevel; i++){
169215 WhereLoop *pLoop = pWInfo->a[i].pWLoop;
169216 const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
169217 SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
169218 Table *pTab = pItem->pSTab;
169219 if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
169220 pTab->tabFlags |= TF_MaybeReanalyze;
169221 if( i>=1
169222 && (pLoop->wsFlags & reqFlags)==reqFlags
169223 /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
@@ -168875,12 +169370,12 @@
169370 int ii;
169371 for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
169372 SrcItem *pItem = &pWInfo->pTabList->a[ii];
169373 if( !pItem->fg.isCte
169374 || pItem->u2.pCteUse->eM10d!=M10d_Yes
169375 || NEVER(pItem->fg.isSubquery==0)
169376 || pItem->u4.pSubq->pSelect->pOrderBy==0
169377 ){
169378 pWInfo->revMask |= MASKBIT(ii);
169379 }
169380 }
169381 }
@@ -169366,19 +169861,19 @@
169861 */
169862 assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
169863 if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
169864 int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
169865 int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
169866 assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) );
169867 if( bOnerow || (
169868 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
169869 && !IsVirtual(pTabList->a[0].pSTab)
169870 && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
169871 && OptimizationEnabled(db, SQLITE_OnePass)
169872 )){
169873 pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
169874 if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){
169875 if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
169876 bFordelete = OPFLAG_FORDELETE;
169877 }
169878 pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY);
169879 }
@@ -169392,11 +169887,11 @@
169887 Table *pTab; /* Table to open */
169888 int iDb; /* Index of database containing table/index */
169889 SrcItem *pTabItem;
169890
169891 pTabItem = &pTabList->a[pLevel->iFrom];
169892 pTab = pTabItem->pSTab;
169893 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
169894 pLoop = pLevel->pWLoop;
169895 if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
169896 /* Do nothing */
169897 }else
@@ -169463,11 +169958,11 @@
169958 /* This is one term of an OR-optimization using the PRIMARY KEY of a
169959 ** WITHOUT ROWID table. No need for a separate index */
169960 iIndexCur = pLevel->iTabCur;
169961 op = 0;
169962 }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
169963 Index *pJ = pTabItem->pSTab->pIndex;
169964 iIndexCur = iAuxArg;
169965 assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
169966 while( ALWAYS(pJ) && pJ!=pIx ){
169967 iIndexCur++;
169968 pJ = pJ->pNext;
@@ -169530,11 +170025,11 @@
170025 pRJ->iMatch = pParse->nTab++;
170026 pRJ->regBloom = ++pParse->nMem;
170027 sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
170028 pRJ->regReturn = ++pParse->nMem;
170029 sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
170030 assert( pTab==pTabItem->pSTab );
170031 if( HasRowid(pTab) ){
170032 KeyInfo *pInfo;
170033 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
170034 pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
170035 if( pInfo ){
@@ -169569,17 +170064,22 @@
170064 if( pParse->nErr ) goto whereBeginError;
170065 pLevel = &pWInfo->a[ii];
170066 wsFlags = pLevel->pWLoop->wsFlags;
170067 pSrc = &pTabList->a[pLevel->iFrom];
170068 if( pSrc->fg.isMaterialized ){
170069 Subquery *pSubq;
170070 int iOnce = 0;
170071 assert( pSrc->fg.isSubquery );
170072 pSubq = pSrc->u4.pSubq;
170073 if( pSrc->fg.isCorrelated==0 ){
170074 iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
170075 }else{
170076 iOnce = 0;
 
 
170077 }
170078 sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub);
170079 VdbeComment((v, "materialize %!S", pSrc));
170080 if( iOnce ) sqlite3VdbeJumpHere(v, iOnce);
170081 }
170082 assert( pTabList == pWInfo->pTabList );
170083 if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
170084 if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
170085 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -169788,13 +170288,14 @@
170288 if( (ws & WHERE_IDX_ONLY)==0 ){
170289 SrcItem *pSrc = &pTabList->a[pLevel->iFrom];
170290 assert( pLevel->iTabCur==pSrc->iCursor );
170291 if( pSrc->fg.viaCoroutine ){
170292 int m, n;
170293 assert( pSrc->fg.isSubquery );
170294 n = pSrc->u4.pSubq->regResult;
170295 assert( pSrc->pSTab!=0 );
170296 m = pSrc->pSTab->nCol;
170297 sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1);
170298 }
170299 sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
170300 }
170301 if( (ws & WHERE_INDEXED)
@@ -169814,20 +170315,20 @@
170315 sqlite3VdbeGoto(v, pLevel->addrFirst);
170316 }
170317 sqlite3VdbeJumpHere(v, addr);
170318 }
170319 VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
170320 pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName));
170321 }
170322
170323 assert( pWInfo->nLevel<=pTabList->nSrc );
170324 for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
170325 int k, last;
170326 VdbeOp *pOp, *pLastOp;
170327 Index *pIdx = 0;
170328 SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
170329 Table *pTab = pTabItem->pSTab;
170330 assert( pTab!=0 );
170331 pLoop = pLevel->pWLoop;
170332
170333 /* Do RIGHT JOIN processing. Generate code that will output the
170334 ** unmatched rows of the right operand of the RIGHT JOIN with
@@ -169842,13 +170343,14 @@
170343 ** the co-routine into OP_Copy of result contained in a register.
170344 ** OP_Rowid becomes OP_Null.
170345 */
170346 if( pTabItem->fg.viaCoroutine ){
170347 testcase( pParse->db->mallocFailed );
170348 assert( pTabItem->fg.isSubquery );
170349 assert( pTabItem->u4.pSubq->regResult>=0 );
170350 translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
170351 pTabItem->u4.pSubq->regResult, 0);
170352 continue;
170353 }
170354
170355 /* If this scan uses an index, make VDBE code substitutions to read data
170356 ** from the index instead of from the table where possible. In some cases
@@ -171054,13 +171556,14 @@
171556 p->selId, p));
171557 p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
171558 assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
171559 ** of sqlite3DbMallocRawNN() called from
171560 ** sqlite3SrcListAppend() */
171561 if( p->pSrc==0 ){
171562 sqlite3SelectDelete(db, pSub);
171563 }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){
171564 Table *pTab2;
 
171565 p->pSrc->a[0].fg.isCorrelated = 1;
171566 sqlite3SrcListAssignCursors(pParse, p->pSrc);
171567 pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
171568 pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
171569 pSub->selFlags |= (selFlags & SF_Aggregate);
@@ -171070,20 +171573,18 @@
171573 ** the correct error message regardless. */
171574 rc = SQLITE_NOMEM;
171575 }else{
171576 memcpy(pTab, pTab2, sizeof(Table));
171577 pTab->tabFlags |= TF_Ephemeral;
171578 p->pSrc->a[0].pSTab = pTab;
171579 pTab = pTab2;
171580 memset(&w, 0, sizeof(w));
171581 w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
171582 w.xSelectCallback = sqlite3WalkerDepthIncrease;
171583 w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
171584 sqlite3WalkSelect(&w, pSub);
171585 }
 
 
171586 }
171587 if( db->mallocFailed ) rc = SQLITE_NOMEM;
171588
171589 /* Defer deleting the temporary table pTab because if an error occurred,
171590 ** there could still be references to that table embedded in the
@@ -171366,14 +171867,19 @@
171867 ** This is called by code in select.c before it calls sqlite3WhereBegin()
171868 ** to begin iterating through the sub-query results. It is used to allocate
171869 ** and initialize registers and cursors used by sqlite3WindowCodeStep().
171870 */
171871 SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
 
 
171872 Window *pWin;
171873 int nEphExpr;
171874 Window *pMWin;
171875 Vdbe *v;
171876
171877 assert( pSelect->pSrc->a[0].fg.isSubquery );
171878 nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr;
171879 pMWin = pSelect->pWin;
171880 v = sqlite3GetVdbe(pParse);
171881
171882 sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
171883 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
171884 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
171885 sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
@@ -172766,11 +173272,11 @@
173272 Window *pMWin = p->pWin;
173273 ExprList *pOrderBy = pMWin->pOrderBy;
173274 Vdbe *v = sqlite3GetVdbe(pParse);
173275 int csrWrite; /* Cursor used to write to eph. table */
173276 int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
173277 int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */
173278 int iInput; /* To iterate through sub cols */
173279 int addrNe; /* Address of OP_Ne */
173280 int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
173281 int addrInteger = 0; /* Address of OP_Integer */
173282 int addrEmpty; /* Address of OP_Rewind in flush: */
@@ -177217,24 +177723,33 @@
177723 }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){
177724 yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269);
177725 if( yymsp[-5].minor.yy203 ){
177726 SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1];
177727 SrcItem *pOld = yymsp[-3].minor.yy203->a;
177728 assert( pOld->fg.fixedSchema==0 );
177729 pNew->zName = pOld->zName;
177730 assert( pOld->fg.fixedSchema==0 );
177731 if( pOld->fg.isSubquery ){
177732 pNew->fg.isSubquery = 1;
177733 pNew->u4.pSubq = pOld->u4.pSubq;
177734 pOld->u4.pSubq = 0;
177735 pOld->fg.isSubquery = 0;
177736 assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 );
177737 if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){
177738 pNew->fg.isNestedFrom = 1;
177739 }
177740 }else{
177741 pNew->u4.zDatabase = pOld->u4.zDatabase;
177742 pOld->u4.zDatabase = 0;
177743 }
177744 if( pOld->fg.isTabFunc ){
177745 pNew->u1.pFuncArg = pOld->u1.pFuncArg;
177746 pOld->u1.pFuncArg = 0;
177747 pOld->fg.isTabFunc = 0;
177748 pNew->fg.isTabFunc = 1;
177749 }
177750 pOld->zName = 0;
 
177751 }
177752 sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203);
177753 }else{
177754 Select *pSubquery;
177755 sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203);
@@ -182324,11 +182839,12 @@
182839 }
182840
182841 assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
182842 assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
182843 extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
182844 SQLITE_SUBTYPE|SQLITE_INNOCUOUS|
182845 SQLITE_RESULT_SUBTYPE|SQLITE_SELFORDER1);
182846 enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
182847
182848 /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
182849 ** the meaning is inverted. So flip the bit. */
182850 assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
@@ -184790,10 +185306,22 @@
185306 case SQLITE_TESTCTRL_OPTIMIZATIONS: {
185307 sqlite3 *db = va_arg(ap, sqlite3*);
185308 db->dbOptFlags = va_arg(ap, u32);
185309 break;
185310 }
185311
185312 /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N)
185313 **
185314 ** Write the current optimization settings into *N. A zero bit means that
185315 ** the optimization is on, and a 1 bit means that the optimization is off.
185316 */
185317 case SQLITE_TESTCTRL_GETOPT: {
185318 sqlite3 *db = va_arg(ap, sqlite3*);
185319 int *pN = va_arg(ap, int*);
185320 *pN = db->dbOptFlags;
185321 break;
185322 }
185323
185324 /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
185325 **
185326 ** If parameter onoff is 1, subsequent calls to localtime() fail.
185327 ** If 2, then invoke xAlt() instead of localtime(). If 0, normal
@@ -224464,10 +224992,11 @@
224992 )
224993 ){
224994 pIdxInfo->orderByConsumed = 1;
224995 pIdxInfo->idxNum |= 0x08;
224996 }
224997 pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX;
224998
224999 return SQLITE_OK;
225000 }
225001
225002 /*
@@ -232374,13 +232903,36 @@
232903 ** It is the output of the tokenizer module. For tokendata=1 tables, this
232904 ** includes any embedded 0x00 and trailing data.
232905 **
232906 ** This API can be quite slow if used with an FTS5 table created with the
232907 ** "detail=none" or "detail=column" option.
232908 **
232909 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
232910 ** If parameter iCol is less than zero, or greater than or equal to the
232911 ** number of columns in the table, SQLITE_RANGE is returned.
232912 **
232913 ** Otherwise, this function attempts to retrieve the locale associated
232914 ** with column iCol of the current row. Usually, there is no associated
232915 ** locale, and output parameters (*pzLocale) and (*pnLocale) are set
232916 ** to NULL and 0, respectively. However, if the fts5_locale() function
232917 ** was used to associate a locale with the value when it was inserted
232918 ** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
232919 ** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
232920 ** is set to the size in bytes of the buffer, not including the
232921 ** nul-terminator.
232922 **
232923 ** If successful, SQLITE_OK is returned. Or, if an error occurs, an
232924 ** SQLite error code is returned. The final value of the output parameters
232925 ** is undefined in this case.
232926 **
232927 ** xTokenize_v2:
232928 ** Tokenize text using the tokenizer belonging to the FTS5 table. This
232929 ** API is the same as the xTokenize() API, except that it allows a tokenizer
232930 ** locale to be specified.
232931 */
232932 struct Fts5ExtensionApi {
232933 int iVersion; /* Currently always set to 4 */
232934
232935 void *(*xUserData)(Fts5Context*);
232936
232937 int (*xColumnCount)(Fts5Context*);
232938 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -232418,10 +232970,19 @@
232970 int (*xQueryToken)(Fts5Context*,
232971 int iPhrase, int iToken,
232972 const char **ppToken, int *pnToken
232973 );
232974 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
232975
232976 /* Below this point are iVersion>=4 only */
232977 int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
232978 int (*xTokenize_v2)(Fts5Context*,
232979 const char *pText, int nText, /* Text to tokenize */
232980 const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
232981 void *pCtx, /* Context passed to xToken() */
232982 int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
232983 );
232984 };
232985
232986 /*
232987 ** CUSTOM AUXILIARY FUNCTIONS
232988 *************************************************************************/
@@ -232430,19 +232991,20 @@
232991 ** CUSTOM TOKENIZERS
232992 **
232993 ** Applications may also register custom tokenizer types. A tokenizer
232994 ** is registered by providing fts5 with a populated instance of the
232995 ** following structure. All structure methods must be defined, setting
232996 **
232997 ** any member of the fts5_tokenizer struct to NULL leads to undefined
232998 ** behaviour. The structure methods are expected to function as follows:
232999 **
233000 ** xCreate:
233001 ** This function is used to allocate and initialize a tokenizer instance.
233002 ** A tokenizer instance is required to actually tokenize text.
233003 **
233004 ** The first argument passed to this function is a copy of the (void*)
233005 ** pointer provided by the application when the fts5_tokenizer_v2 object
233006 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
233007 ** The second and third arguments are an array of nul-terminated strings
233008 ** containing the tokenizer arguments, if any, specified following the
233009 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
233010 ** to create the FTS5 table.
@@ -232462,11 +233024,11 @@
233024 ** This function is expected to tokenize the nText byte string indicated
233025 ** by argument pText. pText may or may not be nul-terminated. The first
233026 ** argument passed to this function is a pointer to an Fts5Tokenizer object
233027 ** returned by an earlier call to xCreate().
233028 **
233029 ** The third argument indicates the reason that FTS5 is requesting
233030 ** tokenization of the supplied text. This is always one of the following
233031 ** four values:
233032 **
233033 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
233034 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -232485,10 +233047,17 @@
233047 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
233048 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
233049 ** function. Or an fts5_api.xColumnSize() request made by the same
233050 ** on a columnsize=0 database.
233051 ** </ul>
233052 **
233053 ** The sixth and seventh arguments passed to xTokenize() - pLocale and
233054 ** nLocale - are a pointer to a buffer containing the locale to use for
233055 ** tokenization (e.g. "en_US") and its size in bytes, respectively. The
233056 ** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
233057 ** which case nLocale is always 0) to indicate that the tokenizer should
233058 ** use its default locale.
233059 **
233060 ** For each token in the input string, the supplied callback xToken() must
233061 ** be invoked. The first argument to it should be a copy of the pointer
233062 ** passed as the second argument to xTokenize(). The third and fourth
233063 ** arguments are a pointer to a buffer containing the token text, and the
@@ -232508,10 +233077,34 @@
233077 ** immediately return a copy of the xToken() return value. Or, if the
233078 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
233079 ** if an error occurs with the xTokenize() implementation itself, it
233080 ** may abandon the tokenization and return any error code other than
233081 ** SQLITE_OK or SQLITE_DONE.
233082 **
233083 ** If the tokenizer is registered using an fts5_tokenizer_v2 object,
233084 ** then the xTokenize() method has two additional arguments - pLocale
233085 ** and nLocale. These specify the locale that the tokenizer should use
233086 ** for the current request. If pLocale and nLocale are both 0, then the
233087 ** tokenizer should use its default locale. Otherwise, pLocale points to
233088 ** an nLocale byte buffer containing the name of the locale to use as utf-8
233089 ** text. pLocale is not nul-terminated.
233090 **
233091 ** FTS5_TOKENIZER
233092 **
233093 ** There is also an fts5_tokenizer object. This is an older, deprecated,
233094 ** version of fts5_tokenizer_v2. It is similar except that:
233095 **
233096 ** <ul>
233097 ** <li> There is no "iVersion" field, and
233098 ** <li> The xTokenize() method does not take a locale argument.
233099 ** </ul>
233100 **
233101 ** Legacy fts5_tokenizer tokenizers must be registered using the
233102 ** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
233103 **
233104 ** Tokenizer implementations registered using either API may be retrieved
233105 ** using both xFindTokenizer() and xFindTokenizer_v2().
233106 **
233107 ** SYNONYM SUPPORT
233108 **
233109 ** Custom tokenizers may also support synonyms. Consider a case in which a
233110 ** user wishes to query for a phrase such as "first place". Using the
@@ -232617,10 +233210,37 @@
233210 ** provide synonyms when tokenizing document text (method (3)) or query
233211 ** text (method (2)), not both. Doing so will not cause any errors, but is
233212 ** inefficient.
233213 */
233214 typedef struct Fts5Tokenizer Fts5Tokenizer;
233215 typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
233216 struct fts5_tokenizer_v2 {
233217 int iVersion; /* Currently always 2 */
233218
233219 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
233220 void (*xDelete)(Fts5Tokenizer*);
233221 int (*xTokenize)(Fts5Tokenizer*,
233222 void *pCtx,
233223 int flags, /* Mask of FTS5_TOKENIZE_* flags */
233224 const char *pText, int nText,
233225 const char *pLocale, int nLocale,
233226 int (*xToken)(
233227 void *pCtx, /* Copy of 2nd argument to xTokenize() */
233228 int tflags, /* Mask of FTS5_TOKEN_* flags */
233229 const char *pToken, /* Pointer to buffer containing token */
233230 int nToken, /* Size of token in bytes */
233231 int iStart, /* Byte offset of token within input text */
233232 int iEnd /* Byte offset of end of token within input text */
233233 )
233234 );
233235 };
233236
233237 /*
233238 ** New code should use the fts5_tokenizer_v2 type to define tokenizer
233239 ** implementations. The following type is included for legacy applications
233240 ** that still use it.
233241 */
233242 typedef struct fts5_tokenizer fts5_tokenizer;
233243 struct fts5_tokenizer {
233244 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
233245 void (*xDelete)(Fts5Tokenizer*);
233246 int (*xTokenize)(Fts5Tokenizer*,
@@ -232635,10 +233255,11 @@
233255 int iStart, /* Byte offset of token within input text */
233256 int iEnd /* Byte offset of end of token within input text */
233257 )
233258 );
233259 };
233260
233261
233262 /* Flags that may be passed as the third argument to xTokenize() */
233263 #define FTS5_TOKENIZE_QUERY 0x0001
233264 #define FTS5_TOKENIZE_PREFIX 0x0002
233265 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -232655,11 +233276,11 @@
233276 /*************************************************************************
233277 ** FTS5 EXTENSION REGISTRATION API
233278 */
233279 typedef struct fts5_api fts5_api;
233280 struct fts5_api {
233281 int iVersion; /* Currently always set to 3 */
233282
233283 /* Create a new tokenizer */
233284 int (*xCreateTokenizer)(
233285 fts5_api *pApi,
233286 const char *zName,
@@ -232682,10 +233303,29 @@
233303 const char *zName,
233304 void *pUserData,
233305 fts5_extension_function xFunction,
233306 void (*xDestroy)(void*)
233307 );
233308
233309 /* APIs below this point are only available if iVersion>=3 */
233310
233311 /* Create a new tokenizer */
233312 int (*xCreateTokenizer_v2)(
233313 fts5_api *pApi,
233314 const char *zName,
233315 void *pUserData,
233316 fts5_tokenizer_v2 *pTokenizer,
233317 void (*xDestroy)(void*)
233318 );
233319
233320 /* Find an existing tokenizer */
233321 int (*xFindTokenizer_v2)(
233322 fts5_api *pApi,
233323 const char *zName,
233324 void **ppUserData,
233325 fts5_tokenizer_v2 **ppTokenizer
233326 );
233327 };
233328
233329 /*
233330 ** END OF REGISTRATION API
233331 *************************************************************************/
@@ -232858,14 +233498,17 @@
233498 typedef struct Fts5Config Fts5Config;
233499 typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
233500
233501 struct Fts5TokenizerConfig {
233502 Fts5Tokenizer *pTok;
233503 fts5_tokenizer_v2 *pApi2;
233504 fts5_tokenizer *pApi1;
233505 const char **azArg;
233506 int nArg;
233507 int ePattern; /* FTS_PATTERN_XXX constant */
233508 const char *pLocale; /* Current locale to use */
233509 int nLocale; /* Size of pLocale in bytes */
233510 };
233511
233512 /*
233513 ** An instance of the following structure encodes all information that can
233514 ** be gleaned from the CREATE VIRTUAL TABLE statement.
@@ -232902,10 +233545,12 @@
233545 ** This is only used for debugging. If set to false, any prefix indexes
233546 ** are ignored. This value is configured using:
233547 **
233548 ** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
233549 **
233550 ** bLocale:
233551 ** Set to true if locale=1 was specified when the table was created.
233552 */
233553 struct Fts5Config {
233554 sqlite3 *db; /* Database handle */
233555 Fts5Global *pGlobal; /* Global fts5 object for handle db */
233556 char *zDb; /* Database holding FTS index (e.g. "main") */
@@ -232919,14 +233564,16 @@
233564 int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
233565 char *zContent; /* content table */
233566 char *zContentRowid; /* "content_rowid=" option value */
233567 int bColumnsize; /* "columnsize=" option value (dflt==1) */
233568 int bTokendata; /* "tokendata=" option value (dflt==0) */
233569 int bLocale; /* "locale=" option value (dflt==0) */
233570 int eDetail; /* FTS5_DETAIL_XXX value */
233571 char *zContentExprlist;
233572 Fts5TokenizerConfig t;
233573 int bLock; /* True when table is preparing statement */
233574
233575
233576 /* Values loaded from the %_config table */
233577 int iVersion; /* fts5 file format 'version' */
233578 int iCookie; /* Incremented when %_config is modified */
233579 int pgsz; /* Approximate page size used in %_data */
@@ -232988,10 +233635,12 @@
233635 /* Set the value of a single config attribute */
233636 static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
233637
233638 static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
233639
233640 static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
233641
233642 /*
233643 ** End of interface to code in fts5_config.c.
233644 **************************************************************************/
233645
233646 /**************************************************************************
@@ -233032,11 +233681,11 @@
233681
233682 /* Write and decode big-endian 32-bit integer values */
233683 static void sqlite3Fts5Put32(u8*, int);
233684 static int sqlite3Fts5Get32(const u8*);
233685
233686 #define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
233687 #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
233688
233689 typedef struct Fts5PoslistReader Fts5PoslistReader;
233690 struct Fts5PoslistReader {
233691 /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
@@ -233323,10 +233972,21 @@
233972
233973 static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
233974
233975 static int sqlite3Fts5FlushToDisk(Fts5Table*);
233976
233977 static int sqlite3Fts5ExtractText(
233978 Fts5Config *pConfig,
233979 sqlite3_value *pVal, /* Value to extract text from */
233980 int bContent, /* Loaded from content table */
233981 int *pbResetTokenizer, /* OUT: True if ClearLocale() required */
233982 const char **ppText, /* OUT: Pointer to text buffer */
233983 int *pnText /* OUT: Size of (*ppText) in bytes */
233984 );
233985
233986 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
233987
233988 /*
233989 ** End of interface to code in fts5.c.
233990 **************************************************************************/
233991
233992 /**************************************************************************
@@ -233402,11 +234062,11 @@
234062 static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
234063
234064 static int sqlite3Fts5DropAll(Fts5Config*);
234065 static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
234066
234067 static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
234068 static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
234069 static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
234070
234071 static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
234072
@@ -233428,10 +234088,13 @@
234088 static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
234089 static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
234090 static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
234091 static int sqlite3Fts5StorageReset(Fts5Storage *p);
234092
234093 static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
234094 static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
234095
234096 /*
234097 ** End of interface to code in fts5_storage.c.
234098 **************************************************************************/
234099
234100
@@ -235357,10 +236020,11 @@
236020 p->iOff = iEndOff;
236021 }
236022
236023 return rc;
236024 }
236025
236026
236027 /*
236028 ** Implementation of highlight() function.
236029 */
236030 static void fts5HighlightFunction(
@@ -235388,16 +236052,23 @@
236052 rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
236053 if( rc==SQLITE_RANGE ){
236054 sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
236055 rc = SQLITE_OK;
236056 }else if( ctx.zIn ){
236057 const char *pLoc = 0; /* Locale of column iCol */
236058 int nLoc = 0; /* Size of pLoc in bytes */
236059 if( rc==SQLITE_OK ){
236060 rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
236061 }
236062
236063 if( rc==SQLITE_OK ){
236064 rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
236065 }
236066 if( rc==SQLITE_OK ){
236067 rc = pApi->xTokenize_v2(
236068 pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
236069 );
236070 }
236071 if( ctx.bOpen ){
236072 fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
236073 }
236074 fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
@@ -235590,19 +236261,23 @@
236261 }
236262
236263 memset(&sFinder, 0, sizeof(Fts5SFinder));
236264 for(i=0; i<nCol; i++){
236265 if( iCol<0 || iCol==i ){
236266 const char *pLoc = 0; /* Locale of column iCol */
236267 int nLoc = 0; /* Size of pLoc in bytes */
236268 int nDoc;
236269 int nDocsize;
236270 int ii;
236271 sFinder.iPos = 0;
236272 sFinder.nFirst = 0;
236273 rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
236274 if( rc!=SQLITE_OK ) break;
236275 rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
236276 if( rc!=SQLITE_OK ) break;
236277 rc = pApi->xTokenize_v2(pFts,
236278 sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
236279 );
236280 if( rc!=SQLITE_OK ) break;
236281 rc = pApi->xColumnSize(pFts, i, &nDocsize);
236282 if( rc!=SQLITE_OK ) break;
236283
@@ -235656,10 +236331,13 @@
236331 }
236332 if( rc==SQLITE_OK && nColSize==0 ){
236333 rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
236334 }
236335 if( ctx.zIn ){
236336 const char *pLoc = 0; /* Locale of column iBestCol */
236337 int nLoc = 0; /* Bytes in pLoc */
236338
236339 if( rc==SQLITE_OK ){
236340 rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
236341 }
236342
236343 ctx.iRangeStart = iBestStart;
@@ -235674,11 +236352,16 @@
236352 while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
236353 rc = fts5CInstIterNext(&ctx.iter);
236354 }
236355
236356 if( rc==SQLITE_OK ){
236357 rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
236358 }
236359 if( rc==SQLITE_OK ){
236360 rc = pApi->xTokenize_v2(
236361 pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
236362 );
236363 }
236364 if( ctx.bOpen ){
236365 fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
236366 }
236367 if( ctx.iRangeEnd>=(nColSize-1) ){
@@ -235857,21 +236540,69 @@
236540 sqlite3_result_double(pCtx, -1.0 * score);
236541 }else{
236542 sqlite3_result_error_code(pCtx, rc);
236543 }
236544 }
236545
236546 /*
236547 ** Implementation of fts5_get_locale() function.
236548 */
236549 static void fts5GetLocaleFunction(
236550 const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
236551 Fts5Context *pFts, /* First arg to pass to pApi functions */
236552 sqlite3_context *pCtx, /* Context for returning result/error */
236553 int nVal, /* Number of values in apVal[] array */
236554 sqlite3_value **apVal /* Array of trailing arguments */
236555 ){
236556 int iCol = 0;
236557 int eType = 0;
236558 int rc = SQLITE_OK;
236559 const char *zLocale = 0;
236560 int nLocale = 0;
236561
236562 /* xColumnLocale() must be available */
236563 assert( pApi->iVersion>=4 );
236564
236565 if( nVal!=1 ){
236566 const char *z = "wrong number of arguments to function fts5_get_locale()";
236567 sqlite3_result_error(pCtx, z, -1);
236568 return;
236569 }
236570
236571 eType = sqlite3_value_numeric_type(apVal[0]);
236572 if( eType!=SQLITE_INTEGER ){
236573 const char *z = "non-integer argument passed to function fts5_get_locale()";
236574 sqlite3_result_error(pCtx, z, -1);
236575 return;
236576 }
236577
236578 iCol = sqlite3_value_int(apVal[0]);
236579 if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
236580 sqlite3_result_error_code(pCtx, SQLITE_RANGE);
236581 return;
236582 }
236583
236584 rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
236585 if( rc!=SQLITE_OK ){
236586 sqlite3_result_error_code(pCtx, rc);
236587 return;
236588 }
236589
236590 sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
236591 }
236592
236593 static int sqlite3Fts5AuxInit(fts5_api *pApi){
236594 struct Builtin {
236595 const char *zFunc; /* Function name (nul-terminated) */
236596 void *pUserData; /* User-data pointer */
236597 fts5_extension_function xFunc;/* Callback function */
236598 void (*xDestroy)(void*); /* Destructor function */
236599 } aBuiltin [] = {
236600 { "snippet", 0, fts5SnippetFunction, 0 },
236601 { "highlight", 0, fts5HighlightFunction, 0 },
236602 { "bm25", 0, fts5Bm25Function, 0 },
236603 { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
236604 };
236605 int rc = SQLITE_OK; /* Return code */
236606 int i; /* To iterate through builtin functions */
236607
236608 for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){
@@ -236677,10 +237408,20 @@
237408 }else{
237409 pConfig->bColumnsize = (zArg[0]=='1');
237410 }
237411 return rc;
237412 }
237413
237414 if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
237415 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
237416 *pzErr = sqlite3_mprintf("malformed locale=... directive");
237417 rc = SQLITE_ERROR;
237418 }else{
237419 pConfig->bLocale = (zArg[0]=='1');
237420 }
237421 return rc;
237422 }
237423
237424 if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
237425 const Fts5Enum aDetail[] = {
237426 { "none", FTS5_DETAIL_NONE },
237427 { "full", FTS5_DETAIL_FULL },
@@ -236967,11 +237708,15 @@
237708 */
237709 static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
237710 if( pConfig ){
237711 int i;
237712 if( pConfig->t.pTok ){
237713 if( pConfig->t.pApi1 ){
237714 pConfig->t.pApi1->xDelete(pConfig->t.pTok);
237715 }else{
237716 pConfig->t.pApi2->xDelete(pConfig->t.pTok);
237717 }
237718 }
237719 sqlite3_free((char*)pConfig->t.azArg);
237720 sqlite3_free(pConfig->zDb);
237721 sqlite3_free(pConfig->zName);
237722 for(i=0; i<pConfig->nCol; i++){
@@ -237050,13 +237795,19 @@
237795 if( pText ){
237796 if( pConfig->t.pTok==0 ){
237797 rc = sqlite3Fts5LoadTokenizer(pConfig);
237798 }
237799 if( rc==SQLITE_OK ){
237800 if( pConfig->t.pApi1 ){
237801 rc = pConfig->t.pApi1->xTokenize(
237802 pConfig->t.pTok, pCtx, flags, pText, nText, xToken
237803 );
237804 }else{
237805 rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
237806 pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
237807 );
237808 }
237809 }
237810 }
237811 return rc;
237812 }
237813
@@ -237309,26 +238060,46 @@
238060 if( rc==SQLITE_OK
238061 && iVersion!=FTS5_CURRENT_VERSION
238062 && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
238063 ){
238064 rc = SQLITE_ERROR;
238065 sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
238066 "(found %d, expected %d or %d) - run 'rebuild'",
238067 iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
238068 );
 
 
 
238069 }else{
238070 pConfig->iVersion = iVersion;
238071 }
238072
238073 if( rc==SQLITE_OK ){
238074 pConfig->iCookie = iCookie;
238075 }
238076 return rc;
238077 }
238078
238079 /*
238080 ** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer
238081 ** containing the error message created using printf() style formatting
238082 ** string zFmt and its trailing arguments.
238083 */
238084 static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
238085 va_list ap; /* ... printf arguments */
238086 char *zMsg = 0;
238087
238088 va_start(ap, zFmt);
238089 zMsg = sqlite3_vmprintf(zFmt, ap);
238090 if( pConfig->pzErrmsg ){
238091 assert( *pConfig->pzErrmsg==0 );
238092 *pConfig->pzErrmsg = zMsg;
238093 }else{
238094 sqlite3_free(zMsg);
238095 }
238096
238097 va_end(ap);
238098 }
238099
238100
238101
238102 /*
238103 ** 2014 May 31
238104 **
238105 ** The author disclaims copyright to this source code. In place of
@@ -237614,15 +238385,16 @@
238385 t = fts5ExprGetToken(&sParse, &z, &token);
238386 sqlite3Fts5Parser(pEngine, t, token, &sParse);
238387 }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
238388 sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
238389
238390 assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
238391 assert_expr_depth_ok(sParse.rc, sParse.pExpr);
238392
238393 /* If the LHS of the MATCH expression was a user column, apply the
238394 ** implicit column-filter. */
238395 if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
238396 int n = sizeof(Fts5Colset);
238397 Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
238398 if( pColset ){
238399 pColset->nCol = 1;
238400 pColset->aiCol[0] = iCol;
@@ -237635,19 +238407,11 @@
238407 *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
238408 if( pNew==0 ){
238409 sParse.rc = SQLITE_NOMEM;
238410 sqlite3Fts5ParseNodeFree(sParse.pExpr);
238411 }else{
238412 pNew->pRoot = sParse.pExpr;
 
 
 
 
 
 
 
 
238413 pNew->pIndex = 0;
238414 pNew->pConfig = pConfig;
238415 pNew->apExprPhrase = sParse.apPhrase;
238416 pNew->nPhrase = sParse.nPhrase;
238417 pNew->bDesc = 0;
@@ -238461,11 +239225,11 @@
239225 pNode->bEof = 1;
239226 return rc;
239227 }
239228 }else{
239229 Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
239230 if( pIter->iRowid==iLast ) continue;
239231 bMatch = 0;
239232 if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
239233 return rc;
239234 }
239235 }
@@ -238983,13 +239747,10 @@
239747 ){
239748 const int SZALLOC = 8;
239749 Fts5ExprNearset *pRet = 0;
239750
239751 if( pParse->rc==SQLITE_OK ){
 
 
 
239752 if( pNear==0 ){
239753 sqlite3_int64 nByte;
239754 nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
239755 pRet = sqlite3_malloc64(nByte);
239756 if( pRet==0 ){
@@ -243382,11 +244143,11 @@
244143 iOff = 4;
244144 }
244145
244146 if( iOff<pIter->iEndofDoclist ){
244147 /* Next entry is on the current page */
244148 u64 iDelta;
244149 iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
244150 pIter->iLeafOffset = iOff;
244151 pIter->iRowid += iDelta;
244152 }else if( (pIter->flags & FTS5_SEGITER_ONETERM)==0 ){
244153 if( pIter->pSeg ){
@@ -250372,15 +251133,32 @@
251133
251134 /*
251135 ** Each tokenizer module registered with the FTS5 module is represented
251136 ** by an object of the following type. All such objects are stored as part
251137 ** of the Fts5Global.pTok list.
251138 **
251139 ** bV2Native:
251140 ** True if the tokenizer was registered using xCreateTokenizer_v2(), false
251141 ** for xCreateTokenizer(). If this variable is true, then x2 is populated
251142 ** with the routines as supplied by the caller and x1 contains synthesized
251143 ** wrapper routines. In this case the user-data pointer passed to
251144 ** x1.xCreate should be a pointer to the Fts5TokenizerModule structure,
251145 ** not a copy of pUserData.
251146 **
251147 ** Of course, if bV2Native is false, then x1 contains the real routines and
251148 ** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule
251149 ** object should be passed to x2.xCreate.
251150 **
251151 ** The synthesized wrapper routines are necessary for xFindTokenizer(_v2)
251152 ** calls.
251153 */
251154 struct Fts5TokenizerModule {
251155 char *zName; /* Name of tokenizer */
251156 void *pUserData; /* User pointer passed to xCreate() */
251157 int bV2Native; /* True if v2 native tokenizer */
251158 fts5_tokenizer x1; /* Tokenizer functions */
251159 fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
251160 void (*xDestroy)(void*); /* Destructor function */
251161 Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
251162 };
251163
251164 struct Fts5FullTable {
@@ -250464,11 +251242,11 @@
251242
251243 /* Auxiliary data storage */
251244 Fts5Auxiliary *pAux; /* Currently executing extension function */
251245 Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
251246
251247 /* Cache used by auxiliary API functions xInst() and xInstCount() */
251248 Fts5PoslistReader *aInstIter; /* One for each phrase */
251249 int nInstAlloc; /* Size of aInst[] array (entries / 3) */
251250 int nInstCount; /* Number of phrase instances */
251251 int *aInst; /* 3 integers per phrase instance */
251252 };
@@ -250499,10 +251277,16 @@
251277 #define FTS5CSR_REQUIRE_POSLIST 0x40
251278
251279 #define BitFlagAllTest(x,y) (((x) & (y))==(y))
251280 #define BitFlagTest(x,y) (((x) & (y))!=0)
251281
251282 /*
251283 ** The subtype value and header bytes used by fts5_locale().
251284 */
251285 #define FTS5_LOCALE_SUBTYPE ((unsigned int)'L')
251286 #define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB"
251287
251288
251289 /*
251290 ** Macros to Set(), Clear() and Test() cursor flags.
251291 */
251292 #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag))
@@ -250673,12 +251457,11 @@
251457 rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
251458 }
251459
251460 /* Load the initial configuration */
251461 if( rc==SQLITE_OK ){
251462 rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1);
 
251463 }
251464
251465 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
251466 rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
251467 }
@@ -250876,11 +251659,11 @@
251659 }else{
251660 if( iCol==nCol+1 ){
251661 if( bSeenRank ) continue;
251662 idxStr[iIdxStr++] = 'r';
251663 bSeenRank = 1;
251664 }else{
251665 nSeenMatch++;
251666 idxStr[iIdxStr++] = 'M';
251667 sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
251668 idxStr += strlen(&idxStr[iIdxStr]);
251669 assert( idxStr[iIdxStr]=='\0' );
@@ -251262,11 +252045,11 @@
252045 rc = SQLITE_NOMEM;
252046 }else{
252047 rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
252048 SQLITE_PREPARE_PERSISTENT, &pRet, 0);
252049 if( rc!=SQLITE_OK ){
252050 sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db));
252051 }
252052 sqlite3_free(zSql);
252053 }
252054
252055 va_end(ap);
@@ -251497,10 +252280,192 @@
252280 sqlite3_free(p->p.base.zErrMsg);
252281 p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
252282 va_end(ap);
252283 }
252284
252285 /*
252286 ** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
252287 ** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
252288 ** valid until after the final call to sqlite3Fts5Tokenize() that will use
252289 ** the locale.
252290 */
252291 static void fts5SetLocale(
252292 Fts5Config *pConfig,
252293 const char *zLocale,
252294 int nLocale
252295 ){
252296 Fts5TokenizerConfig *pT = &pConfig->t;
252297 pT->pLocale = zLocale;
252298 pT->nLocale = nLocale;
252299 }
252300
252301 /*
252302 ** Clear any locale configured by an earlier call to fts5SetLocale() or
252303 ** sqlite3Fts5ExtractText().
252304 */
252305 static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
252306 fts5SetLocale(pConfig, 0, 0);
252307 }
252308
252309 /*
252310 ** This function is used to extract utf-8 text from an sqlite3_value. This
252311 ** is usually done in order to tokenize it. For example, when:
252312 **
252313 ** * a value is written to an fts5 table,
252314 ** * a value is deleted from an FTS5_CONTENT_NORMAL table,
252315 ** * a value containing a query expression is passed to xFilter()
252316 **
252317 ** and so on.
252318 **
252319 ** This function handles 2 cases:
252320 **
252321 ** 1) Ordinary values. The text can be extracted from these using
252322 ** sqlite3_value_text().
252323 **
252324 ** 2) Combination text/locale blobs created by fts5_locale(). There
252325 ** are several cases for these:
252326 **
252327 ** * Blobs tagged with FTS5_LOCALE_SUBTYPE.
252328 ** * Blobs read from the content table of a locale=1 external-content
252329 ** table, and
252330 ** * Blobs read from the content table of a locale=1 regular
252331 ** content table.
252332 **
252333 ** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER
252334 ** header. It is an error if a blob with the subtype or a blob read
252335 ** from the content table of an external content table does not have
252336 ** the required header. A blob read from the content table of a regular
252337 ** locale=1 table does not have the header. This is to save space.
252338 **
252339 ** If successful, SQLITE_OK is returned and output parameters (*ppText)
252340 ** and (*pnText) are set to point to a buffer containing the extracted utf-8
252341 ** text and its length in bytes, respectively. The buffer is not
252342 ** nul-terminated. It has the same lifetime as the sqlite3_value object
252343 ** from which it is extracted.
252344 **
252345 ** Parameter bContent must be true if the value was read from an indexed
252346 ** column (i.e. not UNINDEXED) of the on disk content.
252347 **
252348 ** If pbResetTokenizer is not NULL and if case (2) is used, then
252349 ** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls
252350 ** use the locale. In this case (*pbResetTokenizer) is set to true before
252351 ** returning, to indicate that the caller must call sqlite3Fts5ClearLocale()
252352 ** to clear the locale after tokenizing the text.
252353 */
252354 static int sqlite3Fts5ExtractText(
252355 Fts5Config *pConfig,
252356 sqlite3_value *pVal, /* Value to extract text from */
252357 int bContent, /* True if indexed table content */
252358 int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */
252359 const char **ppText, /* OUT: Pointer to text buffer */
252360 int *pnText /* OUT: Size of (*ppText) in bytes */
252361 ){
252362 const char *pText = 0;
252363 int nText = 0;
252364 int rc = SQLITE_OK;
252365 int bDecodeBlob = 0;
252366
252367 assert( pbResetTokenizer==0 || *pbResetTokenizer==0 );
252368 assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE );
252369 assert( bContent==0 || sqlite3_value_subtype(pVal)==0 );
252370
252371 if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
252372 if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE
252373 || (bContent && pConfig->bLocale)
252374 ){
252375 bDecodeBlob = 1;
252376 }
252377 }
252378
252379 if( bDecodeBlob ){
252380 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
252381 const u8 *pBlob = sqlite3_value_blob(pVal);
252382 int nBlob = sqlite3_value_bytes(pVal);
252383
252384 /* Unless this blob was read from the %_content table of an
252385 ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale()
252386 ** header. Check for this. If it is not found, return an error. */
252387 if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){
252388 if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
252389 rc = SQLITE_ERROR;
252390 }else{
252391 pBlob += 4;
252392 nBlob -= 4;
252393 }
252394 }
252395
252396 if( rc==SQLITE_OK ){
252397 int nLocale = 0;
252398
252399 for(nLocale=0; nLocale<nBlob; nLocale++){
252400 if( pBlob[nLocale]==0x00 ) break;
252401 }
252402 if( nLocale==nBlob || nLocale==0 ){
252403 rc = SQLITE_ERROR;
252404 }else{
252405 pText = (const char*)&pBlob[nLocale+1];
252406 nText = nBlob-nLocale-1;
252407
252408 if( pbResetTokenizer ){
252409 fts5SetLocale(pConfig, (const char*)pBlob, nLocale);
252410 *pbResetTokenizer = 1;
252411 }
252412 }
252413 }
252414
252415 }else{
252416 pText = (const char*)sqlite3_value_text(pVal);
252417 nText = sqlite3_value_bytes(pVal);
252418 }
252419
252420 *ppText = pText;
252421 *pnText = nText;
252422 return rc;
252423 }
252424
252425 /*
252426 ** Argument pVal is the text of a full-text search expression. It may or
252427 ** may not have been wrapped by fts5_locale(). This function extracts
252428 ** the text of the expression, and sets output variable (*pzText) to
252429 ** point to a nul-terminated buffer containing the expression.
252430 **
252431 ** If pVal was an fts5_locale() value, then fts5SetLocale() is called to
252432 ** set the tokenizer to use the specified locale.
252433 **
252434 ** If output variable (*pbFreeAndReset) is set to true, then the caller
252435 ** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
252436 ** locale, and (b) call sqlite3_free() to free (*pzText).
252437 */
252438 static int fts5ExtractExprText(
252439 Fts5Config *pConfig, /* Fts5 configuration */
252440 sqlite3_value *pVal, /* Value to extract expression text from */
252441 char **pzText, /* OUT: nul-terminated buffer of text */
252442 int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
252443 ){
252444 const char *zText = 0;
252445 int nText = 0;
252446 int rc = SQLITE_OK;
252447 int bReset = 0;
252448
252449 *pbFreeAndReset = 0;
252450 rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, &bReset, &zText, &nText);
252451 if( rc==SQLITE_OK ){
252452 if( bReset ){
252453 *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, zText);
252454 if( rc!=SQLITE_OK ){
252455 sqlite3Fts5ClearLocale(pConfig);
252456 }else{
252457 *pbFreeAndReset = 1;
252458 }
252459 }else{
252460 *pzText = (char*)zText;
252461 }
252462 }
252463
252464 return rc;
252465 }
252466
252467
252468 /*
252469 ** This is the xFilter interface for the virtual table. See
252470 ** the virtual table xFilter method documentation for additional
252471 ** information.
@@ -251532,17 +252497,11 @@
252497 char **pzErrmsg = pConfig->pzErrmsg;
252498 int i;
252499 int iIdxStr = 0;
252500 Fts5Expr *pExpr = 0;
252501
252502 assert( pConfig->bLock==0 );
 
 
 
 
 
 
252503 if( pCsr->ePlan ){
252504 fts5FreeCursorComponents(pCsr);
252505 memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
252506 }
252507
@@ -251562,12 +252521,18 @@
252521 switch( idxStr[iIdxStr++] ){
252522 case 'r':
252523 pRank = apVal[i];
252524 break;
252525 case 'M': {
252526 char *zText = 0;
252527 int bFreeAndReset = 0;
252528 int bInternal = 0;
252529
252530 rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
252531 if( rc!=SQLITE_OK ) goto filter_out;
252532 if( zText==0 ) zText = "";
252533
252534 iCol = 0;
252535 do{
252536 iCol = iCol*10 + (idxStr[iIdxStr]-'0');
252537 iIdxStr++;
252538 }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
@@ -251575,21 +252540,27 @@
252540 if( zText[0]=='*' ){
252541 /* The user has issued a query of the form "MATCH '*...'". This
252542 ** indicates that the MATCH expression is not a full text query,
252543 ** but a request for an internal parameter. */
252544 rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
252545 bInternal = 1;
252546 }else{
252547 char **pzErr = &pTab->p.base.zErrMsg;
252548 rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
252549 if( rc==SQLITE_OK ){
252550 rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
252551 pExpr = 0;
252552 }
 
252553 }
252554
252555 if( bFreeAndReset ){
252556 sqlite3_free(zText);
252557 sqlite3Fts5ClearLocale(pConfig);
252558 }
252559
252560 if( bInternal || rc!=SQLITE_OK ) goto filter_out;
252561
252562 break;
252563 }
252564 case 'L':
252565 case 'G': {
252566 int bGlob = (idxStr[iIdxStr-1]=='G');
@@ -251893,11 +252864,11 @@
252864 ){
252865 int rc = SQLITE_OK;
252866 int eType1 = sqlite3_value_type(apVal[1]);
252867 if( eType1==SQLITE_INTEGER ){
252868 sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
252869 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
252870 }
252871 return rc;
252872 }
252873
252874 static void fts5StorageInsert(
@@ -252017,59 +252988,81 @@
252988 }
252989
252990 /* DELETE */
252991 else if( nArg==1 ){
252992 i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
252993 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
252994 bUpdateOrDelete = 1;
252995 }
252996
252997 /* INSERT or UPDATE */
252998 else{
252999 int eType1 = sqlite3_value_numeric_type(apVal[1]);
253000
253001 /* Ensure that no fts5_locale() values are written to locale=0 tables.
253002 ** And that no blobs except fts5_locale() blobs are written to indexed
253003 ** (i.e. not UNINDEXED) columns of locale=1 tables. */
253004 int ii;
253005 for(ii=0; ii<pConfig->nCol; ii++){
253006 if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){
253007 int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE);
253008 if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0)
253009 || (pConfig->bLocale==0 && bSub)
253010 ){
253011 if( pConfig->bLocale==0 ){
253012 fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
253013 }
253014 rc = SQLITE_MISMATCH;
253015 goto update_out;
253016 }
253017 }
253018 }
253019
253020 if( eType0!=SQLITE_INTEGER ){
253021 /* An INSERT statement. If the conflict-mode is REPLACE, first remove
253022 ** the current entry (if any). */
253023 if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
253024 i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
253025 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
253026 bUpdateOrDelete = 1;
253027 }
253028 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253029 }
253030
253031 /* UPDATE */
253032 else{
253033 i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
253034 i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
253035 if( eType1!=SQLITE_INTEGER ){
253036 rc = SQLITE_MISMATCH;
253037 }else if( iOld!=iNew ){
253038 if( eConflict==SQLITE_REPLACE ){
253039 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253040 if( rc==SQLITE_OK ){
253041 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
253042 }
253043 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253044 }else{
253045 rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld);
253046 if( rc==SQLITE_OK ){
253047 rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid);
253048 }
253049 if( rc==SQLITE_OK ){
253050 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253051 }
253052 if( rc==SQLITE_OK ){
253053 rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
253054 }
253055 }
253056 }else{
253057 rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
253058 fts5StorageInsert(&rc, pTab, apVal, pRowid);
253059 }
253060 bUpdateOrDelete = 1;
253061 sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage);
253062 }
253063
253064 }
253065 }
253066
253067 if( rc==SQLITE_OK
253068 && bUpdateOrDelete
@@ -252082,10 +253075,11 @@
253075 if( rc==SQLITE_OK ){
253076 pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
253077 }
253078 }
253079
253080 update_out:
253081 pTab->p.pConfig->pzErrmsg = 0;
253082 return rc;
253083 }
253084
253085 /*
@@ -252103,13 +253097,15 @@
253097
253098 /*
253099 ** Implementation of xBegin() method.
253100 */
253101 static int fts5BeginMethod(sqlite3_vtab *pVtab){
253102 int rc = fts5NewTransaction((Fts5FullTable*)pVtab);
253103 if( rc==SQLITE_OK ){
253104 fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
253105 }
253106 return rc;
253107 }
253108
253109 /*
253110 ** Implementation of xCommit() method. This is a no-op. The contents of
253111 ** the pending-terms hash-table have already been flushed into the database
@@ -252159,21 +253155,44 @@
253155 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253156 Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
253157 return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
253158 }
253159
253160 /*
253161 ** Implementation of xTokenize_v2() API.
253162 */
253163 static int fts5ApiTokenize_v2(
253164 Fts5Context *pCtx,
253165 const char *pText, int nText,
253166 const char *pLoc, int nLoc,
253167 void *pUserData,
253168 int (*xToken)(void*, int, const char*, int, int, int)
253169 ){
253170 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253171 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253172 int rc = SQLITE_OK;
253173
253174 fts5SetLocale(pTab->pConfig, pLoc, nLoc);
253175 rc = sqlite3Fts5Tokenize(pTab->pConfig,
253176 FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
253177 );
253178 fts5SetLocale(pTab->pConfig, 0, 0);
253179
253180 return rc;
253181 }
253182
253183 /*
253184 ** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0
253185 ** passed as the locale.
253186 */
253187 static int fts5ApiTokenize(
253188 Fts5Context *pCtx,
253189 const char *pText, int nText,
253190 void *pUserData,
253191 int (*xToken)(void*, int, const char*, int, int, int)
253192 ){
253193 return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken);
 
 
 
 
253194 }
253195
253196 static int fts5ApiPhraseCount(Fts5Context *pCtx){
253197 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253198 return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
@@ -252191,53 +253210,76 @@
253210 int *pn
253211 ){
253212 int rc = SQLITE_OK;
253213 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253214 Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
253215
253216 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253217 if( iCol<0 || iCol>=pTab->pConfig->nCol ){
253218 rc = SQLITE_RANGE;
253219 }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){
 
 
253220 *pz = 0;
253221 *pn = 0;
253222 }else{
253223 rc = fts5SeekCursor(pCsr, 0);
253224 if( rc==SQLITE_OK ){
253225 Fts5Config *pConfig = pTab->pConfig;
253226 int bContent = (pConfig->abUnindexed[iCol]==0);
253227 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253228 sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn);
253229 }
253230 }
253231 return rc;
253232 }
253233
253234 /*
253235 ** This is called by various API functions - xInst, xPhraseFirst,
253236 ** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase
253237 ** of the current row. This function works for both detail=full tables (in
253238 ** which case the position-list was read from the fts index) or for other
253239 ** detail= modes if the row content is available.
253240 */
253241 static int fts5CsrPoslist(
253242 Fts5Cursor *pCsr, /* Fts5 cursor object */
253243 int iPhrase, /* Phrase to find position list for */
253244 const u8 **pa, /* OUT: Pointer to position list buffer */
253245 int *pn /* OUT: Size of (*pa) in bytes */
253246 ){
253247 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
253248 int rc = SQLITE_OK;
253249 int bLive = (pCsr->pSorter==0);
253250
253251 if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
253252 rc = SQLITE_RANGE;
253253 }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
253254 && pConfig->eContent==FTS5_CONTENT_NONE
253255 ){
253256 *pa = 0;
253257 *pn = 0;
253258 return SQLITE_OK;
253259 }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
253260 if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
253261 Fts5PoslistPopulator *aPopulator;
253262 int i;
253263
253264 aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
253265 if( aPopulator==0 ) rc = SQLITE_NOMEM;
253266 if( rc==SQLITE_OK ){
253267 rc = fts5SeekCursor(pCsr, 0);
253268 }
253269 for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){
253270 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253271 const char *z = 0;
253272 int n = 0;
253273 int bReset = 0;
253274 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
253275 if( rc==SQLITE_OK ){
253276 rc = sqlite3Fts5ExprPopulatePoslists(
253277 pConfig, pCsr->pExpr, aPopulator, i, z, n
253278 );
253279 }
253280 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253281 }
253282 sqlite3_free(aPopulator);
253283
253284 if( pCsr->pSorter ){
253285 sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid);
@@ -252257,11 +253299,10 @@
253299 }
253300 }else{
253301 *pa = 0;
253302 *pn = 0;
253303 }
 
253304
253305 return rc;
253306 }
253307
253308 /*
@@ -252327,11 +253368,12 @@
253368
253369 aInst = &pCsr->aInst[3 * (nInst-1)];
253370 aInst[0] = iBest;
253371 aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
253372 aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
253373 assert( aInst[1]>=0 );
253374 if( aInst[1]>=nCol ){
253375 rc = FTS5_CORRUPT;
253376 break;
253377 }
253378 sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
253379 }
@@ -252414,20 +253456,25 @@
253456 pCsr->aColumnSize[i] = -1;
253457 }
253458 }
253459 }else{
253460 int i;
253461 rc = fts5SeekCursor(pCsr, 0);
253462 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
253463 if( pConfig->abUnindexed[i]==0 ){
253464 const char *z = 0;
253465 int n = 0;
253466 int bReset = 0;
253467 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1);
253468
253469 pCsr->aColumnSize[i] = 0;
253470 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n);
253471 if( rc==SQLITE_OK ){
253472 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
253473 z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
253474 );
253475 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
253476 }
253477 }
253478 }
253479 }
253480 CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
@@ -252669,13 +253716,76 @@
253716
253717
253718 static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
253719 int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
253720 );
253721
253722 /*
253723 ** The xColumnLocale() API.
253724 */
253725 static int fts5ApiColumnLocale(
253726 Fts5Context *pCtx,
253727 int iCol,
253728 const char **pzLocale,
253729 int *pnLocale
253730 ){
253731 int rc = SQLITE_OK;
253732 Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
253733 Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
253734
253735 *pzLocale = 0;
253736 *pnLocale = 0;
253737
253738 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253739 if( iCol<0 || iCol>=pConfig->nCol ){
253740 rc = SQLITE_RANGE;
253741 }else if(
253742 pConfig->abUnindexed[iCol]==0
253743 && pConfig->eContent!=FTS5_CONTENT_NONE
253744 && pConfig->bLocale
253745 ){
253746 rc = fts5SeekCursor(pCsr, 0);
253747 if( rc==SQLITE_OK ){
253748 /* Load the value into pVal. pVal is a locale/text pair iff:
253749 **
253750 ** 1) It is an SQLITE_BLOB, and
253751 ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the
253752 ** value was loaded from an FTS5_CONTENT_NORMAL table, and
253753 ** 3) It does not begin with an 0x00 byte.
253754 */
253755 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
253756 if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
253757 const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
253758 int nBlob = sqlite3_value_bytes(pVal);
253759 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
253760 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
253761 if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){
253762 rc = SQLITE_ERROR;
253763 }
253764 pBlob += 4;
253765 nBlob -= 4;
253766 }
253767 if( rc==SQLITE_OK ){
253768 int nLocale = 0;
253769 for(nLocale=0; nLocale<nBlob && pBlob[nLocale]!=0x00; nLocale++);
253770 if( nLocale==nBlob || nLocale==0 ){
253771 rc = SQLITE_ERROR;
253772 }else{
253773 /* A locale/text pair */
253774 *pzLocale = (const char*)pBlob;
253775 *pnLocale = nLocale;
253776 }
253777 }
253778 }
253779 }
253780 }
253781
253782 return rc;
253783 }
253784
253785 static const Fts5ExtensionApi sFts5Api = {
253786 4, /* iVersion */
253787 fts5ApiUserData,
253788 fts5ApiColumnCount,
253789 fts5ApiRowCount,
253790 fts5ApiColumnTotalSize,
253791 fts5ApiTokenize,
@@ -252692,11 +253802,13 @@
253802 fts5ApiPhraseFirst,
253803 fts5ApiPhraseNext,
253804 fts5ApiPhraseFirstColumn,
253805 fts5ApiPhraseNextColumn,
253806 fts5ApiQueryToken,
253807 fts5ApiInstToken,
253808 fts5ApiColumnLocale,
253809 fts5ApiTokenize_v2
253810 };
253811
253812 /*
253813 ** Implementation of API function xQueryPhrase().
253814 */
@@ -252743,10 +253855,11 @@
253855 sqlite3_context *context,
253856 int argc,
253857 sqlite3_value **argv
253858 ){
253859 assert( pCsr->pAux==0 );
253860 assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
253861 pCsr->pAux = pAux;
253862 pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
253863 pCsr->pAux = 0;
253864 }
253865
@@ -252755,10 +253868,25 @@
253868 for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
253869 if( pCsr->iCsrId==iCsrId ) break;
253870 }
253871 return pCsr;
253872 }
253873
253874 /*
253875 ** Parameter zFmt is a printf() style formatting string. This function
253876 ** formats it using the trailing arguments and returns the result as
253877 ** an error message to the context passed as the first argument.
253878 */
253879 static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){
253880 char *zErr = 0;
253881 va_list ap;
253882 va_start(ap, zFmt);
253883 zErr = sqlite3_vmprintf(zFmt, ap);
253884 sqlite3_result_error(pCtx, zErr, -1);
253885 sqlite3_free(zErr);
253886 va_end(ap);
253887 }
253888
253889 static void fts5ApiCallback(
253890 sqlite3_context *context,
253891 int argc,
253892 sqlite3_value **argv
@@ -252771,14 +253899,12 @@
253899 assert( argc>=1 );
253900 pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
253901 iCsrId = sqlite3_value_int64(argv[0]);
253902
253903 pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
253904 if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){
253905 fts5ResultError(context, "no such cursor: %lld", iCsrId);
 
 
253906 }else{
253907 sqlite3_vtab *pTab = pCsr->base.pVtab;
253908 fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
253909 sqlite3_free(pTab->zErrMsg);
253910 pTab->zErrMsg = 0;
@@ -252867,10 +253993,61 @@
253993 }
253994
253995 sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
253996 return rc;
253997 }
253998
253999 /*
254000 ** Value pVal was read from column iCol of the FTS5 table. This function
254001 ** returns it to the owner of pCtx via a call to an sqlite3_result_xxx()
254002 ** function. This function deals with the same cases as
254003 ** sqlite3Fts5ExtractText():
254004 **
254005 ** 1) Ordinary values. These can be returned using sqlite3_result_value().
254006 **
254007 ** 2) Blobs from fts5_locale(). The text is extracted from these and
254008 ** returned via sqlite3_result_text(). The locale is discarded.
254009 */
254010 static void fts5ExtractValueFromColumn(
254011 sqlite3_context *pCtx,
254012 Fts5Config *pConfig,
254013 int iCol,
254014 sqlite3_value *pVal
254015 ){
254016 assert( pConfig->eContent!=FTS5_CONTENT_NONE );
254017
254018 if( pConfig->bLocale
254019 && sqlite3_value_type(pVal)==SQLITE_BLOB
254020 && pConfig->abUnindexed[iCol]==0
254021 ){
254022 const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1;
254023 const u8 *pBlob = sqlite3_value_blob(pVal);
254024 int nBlob = sqlite3_value_bytes(pVal);
254025 int ii;
254026
254027 if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){
254028 if( nBlob<SZHDR || memcmp(pBlob, FTS5_LOCALE_HEADER, SZHDR) ){
254029 sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254030 return;
254031 }else{
254032 pBlob += 4;
254033 nBlob -= 4;
254034 }
254035 }
254036
254037 for(ii=0; ii<nBlob && pBlob[ii]; ii++);
254038 if( ii==0 || ii==nBlob ){
254039 sqlite3_result_error_code(pCtx, SQLITE_ERROR);
254040 }else{
254041 const char *pText = (const char*)&pBlob[ii+1];
254042 sqlite3_result_text(pCtx, pText, nBlob-ii-1, SQLITE_TRANSIENT);
254043 }
254044 return;
254045 }
254046
254047 sqlite3_result_value(pCtx, pVal);
254048 }
254049
254050 /*
254051 ** This is the xColumn method, called by SQLite to request a value from
254052 ** the row that the supplied cursor currently points to.
254053 */
@@ -252897,12 +254074,12 @@
254074 ** as the table. Return the cursor integer id number. This value is only
254075 ** useful in that it may be passed as the first argument to an FTS5
254076 ** auxiliary function. */
254077 sqlite3_result_int64(pCtx, pCsr->iCsrId);
254078 }else if( iCol==pConfig->nCol+1 ){
 
254079 /* The value of the "rank" column. */
254080
254081 if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
254082 fts5PoslistBlob(pCtx, pCsr);
254083 }else if(
254084 pCsr->ePlan==FTS5_PLAN_MATCH
254085 || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
@@ -252909,24 +254086,31 @@
254086 ){
254087 if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
254088 fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
254089 }
254090 }
254091 }else{
254092 /* A column created by the user containing values. */
254093 int bNochange = sqlite3_vtab_nochange(pCtx);
254094
254095 if( fts5IsContentless(pTab) ){
254096 if( bNochange && pConfig->bContentlessDelete ){
254097 fts5ResultError(pCtx, "cannot UPDATE a subset of "
254098 "columns on fts5 contentless-delete table: %s", pConfig->zName
254099 );
254100 }
254101 }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
254102 pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
254103 rc = fts5SeekCursor(pCsr, 1);
254104 if( rc==SQLITE_OK ){
254105 sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
254106 fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal);
254107 }
254108 pConfig->pzErrmsg = 0;
254109 }
254110 }
254111
254112 return rc;
254113 }
254114
254115
254116 /*
@@ -253060,53 +254244,216 @@
254244 }
254245 }
254246
254247 return rc;
254248 }
254249
254250 /*
254251 ** This function is used by xCreateTokenizer_v2() and xCreateTokenizer().
254252 ** It allocates and partially populates a new Fts5TokenizerModule object.
254253 ** The new object is already linked into the Fts5Global context before
254254 ** returning.
254255 **
254256 ** If successful, SQLITE_OK is returned and a pointer to the new
254257 ** Fts5TokenizerModule object returned via output parameter (*ppNew). All
254258 ** that is required is for the caller to fill in the methods in
254259 ** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native
254260 ** as appropriate.
254261 **
254262 ** If an error occurs, an SQLite error code is returned and the final value
254263 ** of (*ppNew) undefined.
254264 */
254265 static int fts5NewTokenizerModule(
254266 Fts5Global *pGlobal, /* Global context (one per db handle) */
254267 const char *zName, /* Name of new function */
254268 void *pUserData, /* User data for aux. function */
254269 void(*xDestroy)(void*), /* Destructor for pUserData */
254270 Fts5TokenizerModule **ppNew
254271 ){
254272 int rc = SQLITE_OK;
254273 Fts5TokenizerModule *pNew;
254274 sqlite3_int64 nName; /* Size of zName and its \0 terminator */
254275 sqlite3_int64 nByte; /* Bytes of space to allocate */
254276
254277 nName = strlen(zName) + 1;
254278 nByte = sizeof(Fts5TokenizerModule) + nName;
254279 *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte);
254280 if( pNew ){
254281 pNew->zName = (char*)&pNew[1];
254282 memcpy(pNew->zName, zName, nName);
254283 pNew->pUserData = pUserData;
254284 pNew->xDestroy = xDestroy;
254285 pNew->pNext = pGlobal->pTok;
254286 pGlobal->pTok = pNew;
254287 if( pNew->pNext==0 ){
254288 pGlobal->pDfltTok = pNew;
254289 }
254290 }
254291
254292 return rc;
254293 }
254294
254295 /*
254296 ** An instance of this type is used as the Fts5Tokenizer object for
254297 ** wrapper tokenizers - those that provide access to a v1 tokenizer via
254298 ** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer
254299 ** via the fts5_tokenizer API.
254300 */
254301 typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
254302 struct Fts5VtoVTokenizer {
254303 int bV2Native; /* True if v2 native tokenizer */
254304 fts5_tokenizer x1; /* Tokenizer functions */
254305 fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
254306 Fts5Tokenizer *pReal;
254307 };
254308
254309 /*
254310 ** Create a wrapper tokenizer. The context argument pCtx points to the
254311 ** Fts5TokenizerModule object.
254312 */
254313 static int fts5VtoVCreate(
254314 void *pCtx,
254315 const char **azArg,
254316 int nArg,
254317 Fts5Tokenizer **ppOut
254318 ){
254319 Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx;
254320 Fts5VtoVTokenizer *pNew = 0;
254321 int rc = SQLITE_OK;
254322
254323 pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
254324 if( rc==SQLITE_OK ){
254325 pNew->x1 = pMod->x1;
254326 pNew->x2 = pMod->x2;
254327 pNew->bV2Native = pMod->bV2Native;
254328 if( pMod->bV2Native ){
254329 rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
254330 }else{
254331 rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
254332 }
254333 if( rc!=SQLITE_OK ){
254334 sqlite3_free(pNew);
254335 pNew = 0;
254336 }
254337 }
254338
254339 *ppOut = (Fts5Tokenizer*)pNew;
254340 return rc;
254341 }
254342
254343 /*
254344 ** Delete an Fts5VtoVTokenizer wrapper tokenizer.
254345 */
254346 static void fts5VtoVDelete(Fts5Tokenizer *pTok){
254347 Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254348 if( p ){
254349 if( p->bV2Native ){
254350 p->x2.xDelete(p->pReal);
254351 }else{
254352 p->x1.xDelete(p->pReal);
254353 }
254354 sqlite3_free(p);
254355 }
254356 }
254357
254358
254359 /*
254360 ** xTokenizer method for a wrapper tokenizer that offers the v1 interface
254361 ** (no support for locales).
254362 */
254363 static int fts5V1toV2Tokenize(
254364 Fts5Tokenizer *pTok,
254365 void *pCtx, int flags,
254366 const char *pText, int nText,
254367 int (*xToken)(void*, int, const char*, int, int, int)
254368 ){
254369 Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254370 assert( p->bV2Native );
254371 return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
254372 }
254373
254374 /*
254375 ** xTokenizer method for a wrapper tokenizer that offers the v2 interface
254376 ** (with locale support).
254377 */
254378 static int fts5V2toV1Tokenize(
254379 Fts5Tokenizer *pTok,
254380 void *pCtx, int flags,
254381 const char *pText, int nText,
254382 const char *pLocale, int nLocale,
254383 int (*xToken)(void*, int, const char*, int, int, int)
254384 ){
254385 Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
254386 assert( p->bV2Native==0 );
254387 UNUSED_PARAM2(pLocale,nLocale);
254388 return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
254389 }
254390
254391 /*
254392 ** Register a new tokenizer. This is the implementation of the
254393 ** fts5_api.xCreateTokenizer_v2() method.
254394 */
254395 static int fts5CreateTokenizer_v2(
254396 fts5_api *pApi, /* Global context (one per db handle) */
254397 const char *zName, /* Name of new function */
254398 void *pUserData, /* User data for aux. function */
254399 fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */
254400 void(*xDestroy)(void*) /* Destructor for pUserData */
254401 ){
254402 Fts5Global *pGlobal = (Fts5Global*)pApi;
254403 int rc = SQLITE_OK;
254404
254405 if( pTokenizer->iVersion>2 ){
254406 rc = SQLITE_ERROR;
254407 }else{
254408 Fts5TokenizerModule *pNew = 0;
254409 rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew);
254410 if( pNew ){
254411 pNew->x2 = *pTokenizer;
254412 pNew->bV2Native = 1;
254413 pNew->x1.xCreate = fts5VtoVCreate;
254414 pNew->x1.xTokenize = fts5V1toV2Tokenize;
254415 pNew->x1.xDelete = fts5VtoVDelete;
254416 }
254417 }
254418
254419 return rc;
254420 }
254421
254422 /*
254423 ** The fts5_api.xCreateTokenizer() method.
254424 */
254425 static int fts5CreateTokenizer(
254426 fts5_api *pApi, /* Global context (one per db handle) */
254427 const char *zName, /* Name of new function */
254428 void *pUserData, /* User data for aux. function */
254429 fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
254430 void(*xDestroy)(void*) /* Destructor for pUserData */
254431 ){
254432 Fts5TokenizerModule *pNew = 0;
 
 
 
254433 int rc = SQLITE_OK;
254434
254435 rc = fts5NewTokenizerModule(
254436 (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew
254437 );
254438 if( pNew ){
254439 pNew->x1 = *pTokenizer;
254440 pNew->x2.xCreate = fts5VtoVCreate;
254441 pNew->x2.xTokenize = fts5V2toV1Tokenize;
254442 pNew->x2.xDelete = fts5VtoVDelete;
254443 }
 
 
 
 
 
 
 
 
 
 
254444 return rc;
254445 }
254446
254447 /*
254448 ** Search the global context passed as the first argument for a tokenizer
254449 ** module named zName. If found, return a pointer to the Fts5TokenizerModule
254450 ** object. Otherwise, return NULL.
254451 */
254452 static Fts5TokenizerModule *fts5LocateTokenizer(
254453 Fts5Global *pGlobal, /* Global (one per db handle) object */
254454 const char *zName /* Name of tokenizer module to find */
254455 ){
254456 Fts5TokenizerModule *pMod = 0;
254457
254458 if( zName==0 ){
254459 pMod = pGlobal->pDfltTok;
@@ -253116,10 +254463,40 @@
254463 }
254464 }
254465
254466 return pMod;
254467 }
254468
254469 /*
254470 ** Find a tokenizer. This is the implementation of the
254471 ** fts5_api.xFindTokenizer_v2() method.
254472 */
254473 static int fts5FindTokenizer_v2(
254474 fts5_api *pApi, /* Global context (one per db handle) */
254475 const char *zName, /* Name of tokenizer */
254476 void **ppUserData,
254477 fts5_tokenizer_v2 **ppTokenizer /* Populate this object */
254478 ){
254479 int rc = SQLITE_OK;
254480 Fts5TokenizerModule *pMod;
254481
254482 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
254483 if( pMod ){
254484 if( pMod->bV2Native ){
254485 *ppUserData = pMod->pUserData;
254486 }else{
254487 *ppUserData = (void*)pMod;
254488 }
254489 *ppTokenizer = &pMod->x2;
254490 }else{
254491 *ppTokenizer = 0;
254492 *ppUserData = 0;
254493 rc = SQLITE_ERROR;
254494 }
254495
254496 return rc;
254497 }
254498
254499 /*
254500 ** Find a tokenizer. This is the implementation of the
254501 ** fts5_api.xFindTokenizer() method.
254502 */
@@ -253132,70 +254509,79 @@
254509 int rc = SQLITE_OK;
254510 Fts5TokenizerModule *pMod;
254511
254512 pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
254513 if( pMod ){
254514 if( pMod->bV2Native==0 ){
254515 *ppUserData = pMod->pUserData;
254516 }else{
254517 *ppUserData = (void*)pMod;
254518 }
254519 *pTokenizer = pMod->x1;
254520 }else{
254521 memset(pTokenizer, 0, sizeof(*pTokenizer));
254522 *ppUserData = 0;
254523 rc = SQLITE_ERROR;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254524 }
254525
254526 return rc;
254527 }
254528
254529 /*
254530 ** Attempt to instantiate the tokenizer.
254531 */
254532 static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
254533 const char **azArg = pConfig->t.azArg;
254534 const int nArg = pConfig->t.nArg;
254535 Fts5TokenizerModule *pMod = 0;
254536 int rc = SQLITE_OK;
254537
254538 pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]);
254539 if( pMod==0 ){
254540 assert( nArg>0 );
254541 rc = SQLITE_ERROR;
254542 sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]);
254543 }else{
254544 int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0;
254545 if( pMod->bV2Native ){
254546 xCreate = pMod->x2.xCreate;
254547 pConfig->t.pApi2 = &pMod->x2;
254548 }else{
254549 pConfig->t.pApi1 = &pMod->x1;
254550 xCreate = pMod->x1.xCreate;
254551 }
254552
254553 rc = xCreate(pMod->pUserData,
254554 (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
254555 );
254556
254557 if( rc!=SQLITE_OK ){
254558 if( rc!=SQLITE_NOMEM ){
254559 sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor");
254560 }
254561 }else if( pMod->bV2Native==0 ){
254562 pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
254563 pMod->x1.xCreate, pConfig->t.pTok
254564 );
254565 }
254566 }
254567
254568 if( rc!=SQLITE_OK ){
254569 pConfig->t.pApi1 = 0;
254570 pConfig->t.pApi2 = 0;
254571 pConfig->t.pTok = 0;
254572 }
254573
254574 return rc;
254575 }
254576
254577
254578 /*
254579 ** xDestroy callback passed to sqlite3_create_module(). This is invoked
254580 ** when the db handle is being closed. Free memory associated with
254581 ** tokenizers and aux functions registered with this db handle.
254582 */
254583 static void fts5ModuleDestroy(void *pCtx){
254584 Fts5TokenizerModule *pTok, *pNextTok;
254585 Fts5Auxiliary *pAux, *pNextAux;
254586 Fts5Global *pGlobal = (Fts5Global*)pCtx;
254587
@@ -253212,10 +254598,14 @@
254598 }
254599
254600 sqlite3_free(pGlobal);
254601 }
254602
254603 /*
254604 ** Implementation of the fts5() function used by clients to obtain the
254605 ** API pointer.
254606 */
254607 static void fts5Fts5Func(
254608 sqlite3_context *pCtx, /* Function call context */
254609 int nArg, /* Number of args */
254610 sqlite3_value **apArg /* Function arguments */
254611 ){
@@ -253235,11 +254625,74 @@
254625 int nArg, /* Number of args */
254626 sqlite3_value **apUnused /* Function arguments */
254627 ){
254628 assert( nArg==0 );
254629 UNUSED_PARAM2(nArg, apUnused);
254630 sqlite3_result_text(pCtx, "fts5: 2024-09-02 18:41:59 e6bec37ea1ca51e1d048941ce4c5211d8fc5c5e3556a1441f9c79b036843f9e3", -1, SQLITE_TRANSIENT);
254631 }
254632
254633 /*
254634 ** Implementation of fts5_locale(LOCALE, TEXT) function.
254635 **
254636 ** If parameter LOCALE is NULL, or a zero-length string, then a copy of
254637 ** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
254638 ** text, and the value returned is a blob consisting of:
254639 **
254640 ** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
254641 ** * The LOCALE, as utf-8 text, followed by
254642 ** * 0x00, followed by
254643 ** * The TEXT, as utf-8 text.
254644 **
254645 ** There is no final nul-terminator following the TEXT value.
254646 */
254647 static void fts5LocaleFunc(
254648 sqlite3_context *pCtx, /* Function call context */
254649 int nArg, /* Number of args */
254650 sqlite3_value **apArg /* Function arguments */
254651 ){
254652 const char *zLocale = 0;
254653 int nLocale = 0;
254654 const char *zText = 0;
254655 int nText = 0;
254656
254657 assert( nArg==2 );
254658 UNUSED_PARAM(nArg);
254659
254660 zLocale = (const char*)sqlite3_value_text(apArg[0]);
254661 nLocale = sqlite3_value_bytes(apArg[0]);
254662
254663 zText = (const char*)sqlite3_value_text(apArg[1]);
254664 nText = sqlite3_value_bytes(apArg[1]);
254665
254666 if( zLocale==0 || zLocale[0]=='\0' ){
254667 sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
254668 }else{
254669 u8 *pBlob = 0;
254670 u8 *pCsr = 0;
254671 int nBlob = 0;
254672 const int nHdr = 4;
254673 assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 );
254674
254675 nBlob = nHdr + nLocale + 1 + nText;
254676 pBlob = (u8*)sqlite3_malloc(nBlob);
254677 if( pBlob==0 ){
254678 sqlite3_result_error_nomem(pCtx);
254679 return;
254680 }
254681
254682 pCsr = pBlob;
254683 memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr);
254684 pCsr += nHdr;
254685 memcpy(pCsr, zLocale, nLocale);
254686 pCsr += nLocale;
254687 (*pCsr++) = 0x00;
254688 if( zText ) memcpy(pCsr, zText, nText);
254689 assert( &pCsr[nText]==&pBlob[nBlob] );
254690
254691 sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
254692 sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE);
254693 }
254694 }
254695
254696 /*
254697 ** Return true if zName is the extension on one of the shadow tables used
254698 ** by this module.
@@ -253330,14 +254783,16 @@
254783 rc = SQLITE_NOMEM;
254784 }else{
254785 void *p = (void*)pGlobal;
254786 memset(pGlobal, 0, sizeof(Fts5Global));
254787 pGlobal->db = db;
254788 pGlobal->api.iVersion = 3;
254789 pGlobal->api.xCreateFunction = fts5CreateAux;
254790 pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
254791 pGlobal->api.xFindTokenizer = fts5FindTokenizer;
254792 pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
254793 pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
254794 rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
254795 if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
254796 if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
254797 if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
254798 if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
@@ -253351,10 +254806,17 @@
254806 rc = sqlite3_create_function(
254807 db, "fts5_source_id", 0,
254808 SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
254809 p, fts5SourceIdFunc, 0, 0
254810 );
254811 }
254812 if( rc==SQLITE_OK ){
254813 rc = sqlite3_create_function(
254814 db, "fts5_locale", 2,
254815 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
254816 p, fts5LocaleFunc, 0, 0
254817 );
254818 }
254819 }
254820
254821 /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
254822 ** fts5_test_mi.c is compiled and linked into the executable. And call
@@ -253426,17 +254888,44 @@
254888
254889
254890
254891 /* #include "fts5Int.h" */
254892
254893 /*
254894 ** pSavedRow:
254895 ** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
254896 ** does a by-rowid lookup to retrieve a single row from the %_content
254897 ** table or equivalent external-content table/view.
254898 **
254899 ** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
254900 ** values for a row being UPDATEd. In that case, the SQL statement is
254901 ** not reset and pSavedRow is set to point at it. This is so that the
254902 ** insert operation that follows the delete may access the original
254903 ** row values for any new values for which sqlite3_value_nochange() returns
254904 ** true. i.e. if the user executes:
254905 **
254906 ** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
254907 ** ...
254908 ** UPDATE fts SET a=?, b=? WHERE rowid=?;
254909 **
254910 ** then the value passed to the xUpdate() method of this table as the
254911 ** new.c value is an sqlite3_value_nochange() value. So in this case it
254912 ** must be read from the saved row stored in Fts5Storage.pSavedRow.
254913 **
254914 ** This is necessary - using sqlite3_value_nochange() instead of just having
254915 ** SQLite pass the original value back via xUpdate() - so as not to discard
254916 ** any locale information associated with such values.
254917 **
254918 */
254919 struct Fts5Storage {
254920 Fts5Config *pConfig;
254921 Fts5Index *pIndex;
254922 int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
254923 i64 nTotalRow; /* Total number of rows in FTS table */
254924 i64 *aTotalSize; /* Total sizes of each column */
254925 sqlite3_stmt *pSavedRow;
254926 sqlite3_stmt *aStmt[12];
254927 };
254928
254929
254930 #if FTS5_STMT_SCAN_ASC!=0
254931 # error "FTS5_STMT_SCAN_ASC mismatch"
@@ -253446,18 +254935,19 @@
254935 #endif
254936 #if FTS5_STMT_LOOKUP!=2
254937 # error "FTS5_STMT_LOOKUP mismatch"
254938 #endif
254939
254940 #define FTS5_STMT_LOOKUP2 3
254941 #define FTS5_STMT_INSERT_CONTENT 4
254942 #define FTS5_STMT_REPLACE_CONTENT 5
254943 #define FTS5_STMT_DELETE_CONTENT 6
254944 #define FTS5_STMT_REPLACE_DOCSIZE 7
254945 #define FTS5_STMT_DELETE_DOCSIZE 8
254946 #define FTS5_STMT_LOOKUP_DOCSIZE 9
254947 #define FTS5_STMT_REPLACE_CONFIG 10
254948 #define FTS5_STMT_SCAN 11
254949
254950 /*
254951 ** Prepare the two insert statements - Fts5Storage.pInsertContent and
254952 ** Fts5Storage.pInsertDocsize - if they have not already been prepared.
254953 ** Return SQLITE_OK if successful, or an SQLite error code if an error
@@ -253483,10 +254973,11 @@
254973 if( p->aStmt[eStmt]==0 ){
254974 const char *azStmt[] = {
254975 "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
254976 "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
254977 "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
254978 "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
254979
254980 "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
254981 "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
254982 "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
254983 "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
@@ -253497,10 +254988,12 @@
254988 "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
254989 "SELECT %s FROM %s AS T", /* SCAN */
254990 };
254991 Fts5Config *pC = p->pConfig;
254992 char *zSql = 0;
254993
254994 assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
254995
254996 switch( eStmt ){
254997 case FTS5_STMT_SCAN:
254998 zSql = sqlite3_mprintf(azStmt[eStmt],
254999 pC->zContentExprlist, pC->zContent
@@ -253514,10 +255007,11 @@
255007 pC->zContentRowid
255008 );
255009 break;
255010
255011 case FTS5_STMT_LOOKUP:
255012 case FTS5_STMT_LOOKUP2:
255013 zSql = sqlite3_mprintf(azStmt[eStmt],
255014 pC->zContentExprlist, pC->zContent, pC->zContentRowid
255015 );
255016 break;
255017
@@ -253560,11 +255054,11 @@
255054
255055 if( zSql==0 ){
255056 rc = SQLITE_NOMEM;
255057 }else{
255058 int f = SQLITE_PREPARE_PERSISTENT;
255059 if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
255060 p->pConfig->bLock++;
255061 rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
255062 p->pConfig->bLock--;
255063 sqlite3_free(zSql);
255064 if( rc!=SQLITE_OK && pzErrMsg ){
@@ -253808,74 +255302,141 @@
255302 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
255303 pCtx->szCol++;
255304 }
255305 return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
255306 }
255307
255308 /*
255309 ** This function is used as part of an UPDATE statement that modifies the
255310 ** rowid of a row. In that case, this function is called first to set
255311 ** Fts5Storage.pSavedRow to point to a statement that may be used to
255312 ** access the original values of the row being deleted - iDel.
255313 **
255314 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
255315 ** It is not considered an error if row iDel does not exist. In this case
255316 ** pSavedRow is not set and SQLITE_OK returned.
255317 */
255318 static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
255319 int rc = SQLITE_OK;
255320 sqlite3_stmt *pSeek = 0;
255321
255322 assert( p->pSavedRow==0 );
255323 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
255324 if( rc==SQLITE_OK ){
255325 sqlite3_bind_int64(pSeek, 1, iDel);
255326 if( sqlite3_step(pSeek)!=SQLITE_ROW ){
255327 rc = sqlite3_reset(pSeek);
255328 }else{
255329 p->pSavedRow = pSeek;
255330 }
255331 }
255332
255333 return rc;
255334 }
255335
255336 /*
255337 ** If a row with rowid iDel is present in the %_content table, add the
255338 ** delete-markers to the FTS index necessary to delete it. Do not actually
255339 ** remove the %_content row at this time though.
255340 **
255341 ** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
255342 ** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
255343 ** the original values of the row being deleted. This is used by UPDATE
255344 ** statements.
255345 */
255346 static int fts5StorageDeleteFromIndex(
255347 Fts5Storage *p,
255348 i64 iDel,
255349 sqlite3_value **apVal,
255350 int bSaveRow /* True to set pSavedRow */
255351 ){
255352 Fts5Config *pConfig = p->pConfig;
255353 sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
255354 int rc = SQLITE_OK; /* Return code */
255355 int rc2; /* sqlite3_reset() return code */
255356 int iCol;
255357 Fts5InsertCtx ctx;
255358
255359 assert( bSaveRow==0 || apVal==0 );
255360 assert( bSaveRow==0 || bSaveRow==1 );
255361 assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
255362
255363 if( apVal==0 ){
255364 if( p->pSavedRow && bSaveRow ){
255365 pSeek = p->pSavedRow;
255366 p->pSavedRow = 0;
255367 }else{
255368 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
255369 if( rc!=SQLITE_OK ) return rc;
255370 sqlite3_bind_int64(pSeek, 1, iDel);
255371 if( sqlite3_step(pSeek)!=SQLITE_ROW ){
255372 return sqlite3_reset(pSeek);
255373 }
255374 }
255375 }
255376
255377 ctx.pStorage = p;
255378 ctx.iCol = -1;
255379 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
255380 if( pConfig->abUnindexed[iCol-1]==0 ){
255381 sqlite3_value *pVal = 0;
255382 const char *pText = 0;
255383 int nText = 0;
255384 int bReset = 0;
255385
255386 assert( pSeek==0 || apVal==0 );
255387 assert( pSeek!=0 || apVal!=0 );
255388 if( pSeek ){
255389 pVal = sqlite3_column_value(pSeek, iCol);
 
 
 
 
255390 }else{
255391 pVal = apVal[iCol-1];
255392 }
255393
255394 rc = sqlite3Fts5ExtractText(
255395 pConfig, pVal, pSeek!=0, &bReset, &pText, &nText
255396 );
255397 if( rc==SQLITE_OK ){
255398 ctx.szCol = 0;
255399 rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
255400 pText, nText, (void*)&ctx, fts5StorageInsertCallback
255401 );
255402 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
255403 if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
255404 rc = FTS5_CORRUPT;
255405 }
255406 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255407 }
255408 }
255409 }
255410 if( rc==SQLITE_OK && p->nTotalRow<1 ){
255411 rc = FTS5_CORRUPT;
255412 }else{
255413 p->nTotalRow--;
255414 }
255415
255416 if( rc==SQLITE_OK && bSaveRow ){
255417 assert( p->pSavedRow==0 );
255418 p->pSavedRow = pSeek;
255419 }else{
255420 rc2 = sqlite3_reset(pSeek);
255421 if( rc==SQLITE_OK ) rc = rc2;
255422 }
255423 return rc;
255424 }
255425
255426 /*
255427 ** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
255428 ** should be called by the xUpdate() method of the fts5 table before
255429 ** returning from any operation that may have set Fts5Storage.pSavedRow.
255430 */
255431 static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
255432 assert( pStorage->pSavedRow==0
255433 || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
255434 );
255435 sqlite3_reset(pStorage->pSavedRow);
255436 pStorage->pSavedRow = 0;
255437 }
255438
255439 /*
255440 ** This function is called to process a DELETE on a contentless_delete=1
255441 ** table. It adds the tombstone required to delete the entry with rowid
255442 ** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
@@ -253929,16 +255490,16 @@
255490 if( p->pConfig->bContentlessDelete ){
255491 i64 iOrigin = 0;
255492 rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
255493 sqlite3_bind_int64(pReplace, 3, iOrigin);
255494 }
255495 }
255496 if( rc==SQLITE_OK ){
255497 sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
255498 sqlite3_step(pReplace);
255499 rc = sqlite3_reset(pReplace);
255500 sqlite3_bind_null(pReplace, 2);
255501 }
255502 }
255503 return rc;
255504 }
255505
@@ -253988,11 +255549,16 @@
255549 }
255550
255551 /*
255552 ** Remove a row from the FTS table.
255553 */
255554 static int sqlite3Fts5StorageDelete(
255555 Fts5Storage *p, /* Storage object */
255556 i64 iDel, /* Rowid to delete from table */
255557 sqlite3_value **apVal, /* Optional - values to remove from index */
255558 int bSaveRow /* If true, set pSavedRow for deleted row */
255559 ){
255560 Fts5Config *pConfig = p->pConfig;
255561 int rc;
255562 sqlite3_stmt *pDel = 0;
255563
255564 assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 );
@@ -254005,11 +255571,11 @@
255571
255572 if( rc==SQLITE_OK ){
255573 if( p->pConfig->bContentlessDelete ){
255574 rc = fts5StorageContentlessDelete(p, iDel);
255575 }else{
255576 rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
255577 }
255578 }
255579
255580 /* Delete the %_docsize record */
255581 if( rc==SQLITE_OK && pConfig->bColumnsize ){
@@ -254094,18 +255660,25 @@
255660 sqlite3Fts5BufferZero(&buf);
255661 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255662 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255663 ctx.szCol = 0;
255664 if( pConfig->abUnindexed[ctx.iCol]==0 ){
255665 int bReset = 0; /* True if tokenizer locale must be reset */
255666 int nText = 0; /* Size of pText in bytes */
255667 const char *pText = 0; /* Pointer to buffer containing text value */
255668 sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
255669
255670 rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText);
255671 if( rc==SQLITE_OK ){
255672 rc = sqlite3Fts5Tokenize(pConfig,
255673 FTS5_TOKENIZE_DOCUMENT,
255674 pText, nText,
255675 (void*)&ctx,
255676 fts5StorageInsertCallback
255677 );
255678 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255679 }
255680 }
255681 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255682 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255683 }
255684 p->nTotalRow++;
@@ -254185,11 +255758,35 @@
255758 }else{
255759 sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
255760 int i; /* Counter variable */
255761 rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
255762 for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
255763 sqlite3_value *pVal = apVal[i];
255764 if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
255765 /* This is an UPDATE statement, and column (i-2) was not modified.
255766 ** Retrieve the value from Fts5Storage.pSavedRow instead. */
255767 pVal = sqlite3_column_value(p->pSavedRow, i-1);
255768 }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
255769 assert( pConfig->bLocale );
255770 assert( i>1 );
255771 if( pConfig->abUnindexed[i-2] ){
255772 /* At attempt to insert an fts5_locale() value into an UNINDEXED
255773 ** column. Strip the locale away and just bind the text. */
255774 const char *pText = 0;
255775 int nText = 0;
255776 rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
255777 sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
255778 }else{
255779 const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
255780 int nBlob = sqlite3_value_bytes(pVal);
255781 assert( nBlob>4 );
255782 sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
255783 }
255784 continue;
255785 }
255786
255787 rc = sqlite3_bind_value(pInsert, i, pVal);
255788 }
255789 if( rc==SQLITE_OK ){
255790 sqlite3_step(pInsert);
255791 rc = sqlite3_reset(pInsert);
255792 }
@@ -254220,18 +255817,28 @@
255817 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
255818 }
255819 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
255820 ctx.szCol = 0;
255821 if( pConfig->abUnindexed[ctx.iCol]==0 ){
255822 int bReset = 0; /* True if tokenizer locale must be reset */
255823 int nText = 0; /* Size of pText in bytes */
255824 const char *pText = 0; /* Pointer to buffer containing text value */
255825 sqlite3_value *pVal = apVal[ctx.iCol+2];
255826 int bDisk = 0;
255827 if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
255828 pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
255829 bDisk = 1;
255830 }
255831 rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText);
255832 if( rc==SQLITE_OK ){
255833 assert( bReset==0 || pConfig->bLocale );
255834 rc = sqlite3Fts5Tokenize(pConfig,
255835 FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
255836 fts5StorageInsertCallback
255837 );
255838 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
255839 }
255840 }
255841 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
255842 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
255843 }
255844 p->nTotalRow++;
@@ -254398,18 +256005,26 @@
256005 ctx.szCol = 0;
256006 if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
256007 rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
256008 }
256009 if( rc==SQLITE_OK ){
256010 int bReset = 0; /* True if tokenizer locale must be reset */
256011 int nText = 0; /* Size of pText in bytes */
256012 const char *pText = 0; /* Pointer to buffer containing text value */
256013
256014 rc = sqlite3Fts5ExtractText(pConfig,
256015 sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText
 
256016 );
256017 if( rc==SQLITE_OK ){
256018 rc = sqlite3Fts5Tokenize(pConfig,
256019 FTS5_TOKENIZE_DOCUMENT,
256020 pText, nText,
256021 (void*)&ctx,
256022 fts5StorageIntegrityCallback
256023 );
256024 if( bReset ) sqlite3Fts5ClearLocale(pConfig);
256025 }
256026 }
256027 if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
256028 rc = FTS5_CORRUPT;
256029 }
256030 aTotalSize[i] += ctx.szCol;
@@ -254720,11 +256335,11 @@
256335 rc = SQLITE_NOMEM;
256336 }else{
256337 int i;
256338 memset(p, 0, sizeof(AsciiTokenizer));
256339 memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
256340 for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
256341 const char *zArg = azArg[i+1];
256342 if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
256343 fts5AsciiAddExceptions(p, zArg, 1);
256344 }else
256345 if( 0==sqlite3_stricmp(azArg[i], "separators") ){
@@ -254731,11 +256346,10 @@
256346 fts5AsciiAddExceptions(p, zArg, 0);
256347 }else{
256348 rc = SQLITE_ERROR;
256349 }
256350 }
 
256351 if( rc!=SQLITE_OK ){
256352 fts5AsciiDelete((Fts5Tokenizer*)p);
256353 p = 0;
256354 }
256355 }
@@ -255023,20 +256637,20 @@
256637 if( p->aFold==0 ){
256638 rc = SQLITE_NOMEM;
256639 }
256640
256641 /* Search for a "categories" argument */
256642 for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
256643 if( 0==sqlite3_stricmp(azArg[i], "categories") ){
256644 zCat = azArg[i+1];
256645 }
256646 }
256647 if( rc==SQLITE_OK ){
256648 rc = unicodeSetCategories(p, zCat);
256649 }
256650
256651 for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
256652 const char *zArg = azArg[i+1];
256653 if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
256654 if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
256655 rc = SQLITE_ERROR;
256656 }else{
@@ -255057,12 +256671,10 @@
256671 /* no-op */
256672 }else{
256673 rc = SQLITE_ERROR;
256674 }
256675 }
 
 
256676 }else{
256677 rc = SQLITE_NOMEM;
256678 }
256679 if( rc!=SQLITE_OK ){
256680 fts5UnicodeDelete((Fts5Tokenizer*)p);
@@ -255197,11 +256809,11 @@
256809 ** stemming. */
256810 #define FTS5_PORTER_MAX_TOKEN 64
256811
256812 typedef struct PorterTokenizer PorterTokenizer;
256813 struct PorterTokenizer {
256814 fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
256815 Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
256816 char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
256817 };
256818
256819 /*
@@ -255209,11 +256821,11 @@
256821 */
256822 static void fts5PorterDelete(Fts5Tokenizer *pTok){
256823 if( pTok ){
256824 PorterTokenizer *p = (PorterTokenizer*)pTok;
256825 if( p->pTokenizer ){
256826 p->tokenizer_v2.xDelete(p->pTokenizer);
256827 }
256828 sqlite3_free(p);
256829 }
256830 }
256831
@@ -255228,26 +256840,28 @@
256840 fts5_api *pApi = (fts5_api*)pCtx;
256841 int rc = SQLITE_OK;
256842 PorterTokenizer *pRet;
256843 void *pUserdata = 0;
256844 const char *zBase = "unicode61";
256845 fts5_tokenizer_v2 *pV2 = 0;
256846
256847 if( nArg>0 ){
256848 zBase = azArg[0];
256849 }
256850
256851 pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
256852 if( pRet ){
256853 memset(pRet, 0, sizeof(PorterTokenizer));
256854 rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
256855 }else{
256856 rc = SQLITE_NOMEM;
256857 }
256858 if( rc==SQLITE_OK ){
256859 int nArg2 = (nArg>0 ? nArg-1 : 0);
256860 const char **az2 = (nArg2 ? &azArg[1] : 0);
256861 memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
256862 rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
256863 }
256864
256865 if( rc!=SQLITE_OK ){
256866 fts5PorterDelete((Fts5Tokenizer*)pRet);
256867 pRet = 0;
@@ -255894,19 +257508,20 @@
257508 static int fts5PorterTokenize(
257509 Fts5Tokenizer *pTokenizer,
257510 void *pCtx,
257511 int flags,
257512 const char *pText, int nText,
257513 const char *pLoc, int nLoc,
257514 int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
257515 ){
257516 PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
257517 PorterContext sCtx;
257518 sCtx.xToken = xToken;
257519 sCtx.pCtx = pCtx;
257520 sCtx.aBuf = p->aBuf;
257521 return p->tokenizer_v2.xTokenize(
257522 p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
257523 );
257524 }
257525
257526 /**************************************************************************
257527 ** Start of trigram implementation.
@@ -255932,45 +257547,50 @@
257547 const char **azArg,
257548 int nArg,
257549 Fts5Tokenizer **ppOut
257550 ){
257551 int rc = SQLITE_OK;
257552 TrigramTokenizer *pNew = 0;
257553 UNUSED_PARAM(pUnused);
257554 if( nArg%2 ){
257555 rc = SQLITE_ERROR;
257556 }else{
257557 int i;
257558 pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
257559 if( pNew==0 ){
257560 rc = SQLITE_NOMEM;
257561 }else{
257562 pNew->bFold = 1;
257563 pNew->iFoldParam = 0;
257564
257565 for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
257566 const char *zArg = azArg[i+1];
257567 if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
257568 if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
257569 rc = SQLITE_ERROR;
257570 }else{
257571 pNew->bFold = (zArg[0]=='0');
257572 }
257573 }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
257574 if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
257575 rc = SQLITE_ERROR;
257576 }else{
257577 pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
257578 }
257579 }else{
257580 rc = SQLITE_ERROR;
257581 }
257582 }
257583
257584 if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
257585 rc = SQLITE_ERROR;
257586 }
257587
257588 if( rc!=SQLITE_OK ){
257589 fts5TriDelete((Fts5Tokenizer*)pNew);
257590 pNew = 0;
257591 }
257592 }
257593 }
257594 *ppOut = (Fts5Tokenizer*)pNew;
257595 return rc;
257596 }
@@ -256091,11 +257711,10 @@
257711 const char *zName;
257712 fts5_tokenizer x;
257713 } aBuiltin[] = {
257714 { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
257715 { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
 
257716 { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
257717 };
257718
257719 int rc = SQLITE_OK; /* Return code */
257720 int i; /* To iterate through builtin functions */
@@ -256106,11 +257725,24 @@
257725 (void*)pApi,
257726 &aBuiltin[i].x,
257727 0
257728 );
257729 }
257730 if( rc==SQLITE_OK ){
257731 fts5_tokenizer_v2 sPorter = {
257732 2,
257733 fts5PorterCreate,
257734 fts5PorterDelete,
257735 fts5PorterTokenize
257736 };
257737 rc = pApi->xCreateTokenizer_v2(pApi,
257738 "porter",
257739 (void*)pApi,
257740 &sPorter,
257741 0
257742 );
257743 }
257744 return rc;
257745 }
257746
257747 /*
257748 ** 2012-05-25
@@ -256476,10 +258108,13 @@
258108 aArray[29] = 1;
258109 break;
258110 default: return 1; }
258111 break;
258112
258113
258114 default:
258115 return 1;
258116 }
258117 return 0;
258118 }
258119
258120 static u16 aFts5UnicodeBlock[] = {
258121
+135 -9
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -146,11 +146,11 @@
146146
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147147
** [sqlite_version()] and [sqlite_source_id()].
148148
*/
149149
#define SQLITE_VERSION "3.47.0"
150150
#define SQLITE_VERSION_NUMBER 3047000
151
-#define SQLITE_SOURCE_ID "2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9"
151
+#define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
152152
153153
/*
154154
** CAPI3REF: Run-Time Library Version Numbers
155155
** KEYWORDS: sqlite3_version sqlite3_sourceid
156156
**
@@ -5613,18 +5613,28 @@
56135613
** might become a no-op if the function is used as term in an
56145614
** [expression index]. On the other hand, SQL functions that never invoke
56155615
** [sqlite3_result_subtype()] should avoid setting this property, as the
56165616
** purpose of this property is to disable certain optimizations that are
56175617
** incompatible with subtypes.
5618
+**
5619
+** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
5620
+** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
5621
+** that internally orders the values provided to the first argument. The
5622
+** ordered-set aggregate SQL notation with a single ORDER BY term can be
5623
+** used to invoke this function. If the ordered-set aggregate notation is
5624
+** used on a function that lacks this flag, then an error is raised. Note
5625
+** that the ordered-set aggregate syntax is only available if SQLite is
5626
+** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
56185627
** </dd>
56195628
** </dl>
56205629
*/
56215630
#define SQLITE_DETERMINISTIC 0x000000800
56225631
#define SQLITE_DIRECTONLY 0x000080000
56235632
#define SQLITE_SUBTYPE 0x000100000
56245633
#define SQLITE_INNOCUOUS 0x000200000
56255634
#define SQLITE_RESULT_SUBTYPE 0x001000000
5635
+#define SQLITE_SELFORDER1 0x002000000
56265636
56275637
/*
56285638
** CAPI3REF: Deprecated Functions
56295639
** DEPRECATED
56305640
**
@@ -7425,13 +7435,15 @@
74257435
**
74267436
** ^The estimatedRows value is an estimate of the number of rows that
74277437
** will be returned by the strategy.
74287438
**
74297439
** The xBestIndex method may optionally populate the idxFlags field with a
7430
-** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
7431
-** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
7432
-** assumes that the strategy may visit at most one row.
7440
+** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
7441
+** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
7442
+** output to show the idxNum has hex instead of as decimal. Another flag is
7443
+** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
7444
+** return at most one row.
74337445
**
74347446
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
74357447
** SQLite also assumes that if a call to the xUpdate() method is made as
74367448
** part of the same statement to delete or update a virtual table row and the
74377449
** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7491,11 +7503,13 @@
74917503
**
74927504
** Virtual table implementations are allowed to set the
74937505
** [sqlite3_index_info].idxFlags field to some combination of
74947506
** these bits.
74957507
*/
7496
-#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
7508
+#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
7509
+#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
7510
+ /* in EXPLAIN QUERY PLAN */
74977511
74987512
/*
74997513
** CAPI3REF: Virtual Table Constraint Operator Codes
75007514
**
75017515
** These macros define the allowed values for the
@@ -8328,10 +8342,11 @@
83288342
#define SQLITE_TESTCTRL_ALWAYS 13
83298343
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
83308344
#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
83318345
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
83328346
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
8347
+#define SQLITE_TESTCTRL_GETOPT 16
83338348
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
83348349
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
83358350
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
83368351
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
83378352
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13102,13 +13117,36 @@
1310213117
** It is the output of the tokenizer module. For tokendata=1 tables, this
1310313118
** includes any embedded 0x00 and trailing data.
1310413119
**
1310513120
** This API can be quite slow if used with an FTS5 table created with the
1310613121
** "detail=none" or "detail=column" option.
13122
+**
13123
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
13124
+** If parameter iCol is less than zero, or greater than or equal to the
13125
+** number of columns in the table, SQLITE_RANGE is returned.
13126
+**
13127
+** Otherwise, this function attempts to retrieve the locale associated
13128
+** with column iCol of the current row. Usually, there is no associated
13129
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
13130
+** to NULL and 0, respectively. However, if the fts5_locale() function
13131
+** was used to associate a locale with the value when it was inserted
13132
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
13133
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
13134
+** is set to the size in bytes of the buffer, not including the
13135
+** nul-terminator.
13136
+**
13137
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
13138
+** SQLite error code is returned. The final value of the output parameters
13139
+** is undefined in this case.
13140
+**
13141
+** xTokenize_v2:
13142
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
13143
+** API is the same as the xTokenize() API, except that it allows a tokenizer
13144
+** locale to be specified.
1310713145
*/
1310813146
struct Fts5ExtensionApi {
13109
- int iVersion; /* Currently always set to 3 */
13147
+ int iVersion; /* Currently always set to 4 */
1311013148
1311113149
void *(*xUserData)(Fts5Context*);
1311213150
1311313151
int (*xColumnCount)(Fts5Context*);
1311413152
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13146,10 +13184,19 @@
1314613184
int (*xQueryToken)(Fts5Context*,
1314713185
int iPhrase, int iToken,
1314813186
const char **ppToken, int *pnToken
1314913187
);
1315013188
int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
13189
+
13190
+ /* Below this point are iVersion>=4 only */
13191
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
13192
+ int (*xTokenize_v2)(Fts5Context*,
13193
+ const char *pText, int nText, /* Text to tokenize */
13194
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
13195
+ void *pCtx, /* Context passed to xToken() */
13196
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
13197
+ );
1315113198
};
1315213199
1315313200
/*
1315413201
** CUSTOM AUXILIARY FUNCTIONS
1315513202
*************************************************************************/
@@ -13158,19 +13205,20 @@
1315813205
** CUSTOM TOKENIZERS
1315913206
**
1316013207
** Applications may also register custom tokenizer types. A tokenizer
1316113208
** is registered by providing fts5 with a populated instance of the
1316213209
** following structure. All structure methods must be defined, setting
13210
+**
1316313211
** any member of the fts5_tokenizer struct to NULL leads to undefined
1316413212
** behaviour. The structure methods are expected to function as follows:
1316513213
**
1316613214
** xCreate:
1316713215
** This function is used to allocate and initialize a tokenizer instance.
1316813216
** A tokenizer instance is required to actually tokenize text.
1316913217
**
1317013218
** The first argument passed to this function is a copy of the (void*)
13171
-** pointer provided by the application when the fts5_tokenizer object
13219
+** pointer provided by the application when the fts5_tokenizer_v2 object
1317213220
** was registered with FTS5 (the third argument to xCreateTokenizer()).
1317313221
** The second and third arguments are an array of nul-terminated strings
1317413222
** containing the tokenizer arguments, if any, specified following the
1317513223
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
1317613224
** to create the FTS5 table.
@@ -13190,11 +13238,11 @@
1319013238
** This function is expected to tokenize the nText byte string indicated
1319113239
** by argument pText. pText may or may not be nul-terminated. The first
1319213240
** argument passed to this function is a pointer to an Fts5Tokenizer object
1319313241
** returned by an earlier call to xCreate().
1319413242
**
13195
-** The second argument indicates the reason that FTS5 is requesting
13243
+** The third argument indicates the reason that FTS5 is requesting
1319613244
** tokenization of the supplied text. This is always one of the following
1319713245
** four values:
1319813246
**
1319913247
** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
1320013248
** or removed from the FTS table. The tokenizer is being invoked to
@@ -13213,10 +13261,17 @@
1321313261
** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
1321413262
** satisfy an fts5_api.xTokenize() request made by an auxiliary
1321513263
** function. Or an fts5_api.xColumnSize() request made by the same
1321613264
** on a columnsize=0 database.
1321713265
** </ul>
13266
+**
13267
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
13268
+** nLocale - are a pointer to a buffer containing the locale to use for
13269
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
13270
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
13271
+** which case nLocale is always 0) to indicate that the tokenizer should
13272
+** use its default locale.
1321813273
**
1321913274
** For each token in the input string, the supplied callback xToken() must
1322013275
** be invoked. The first argument to it should be a copy of the pointer
1322113276
** passed as the second argument to xTokenize(). The third and fourth
1322213277
** arguments are a pointer to a buffer containing the token text, and the
@@ -13236,10 +13291,34 @@
1323613291
** immediately return a copy of the xToken() return value. Or, if the
1323713292
** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
1323813293
** if an error occurs with the xTokenize() implementation itself, it
1323913294
** may abandon the tokenization and return any error code other than
1324013295
** SQLITE_OK or SQLITE_DONE.
13296
+**
13297
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
13298
+** then the xTokenize() method has two additional arguments - pLocale
13299
+** and nLocale. These specify the locale that the tokenizer should use
13300
+** for the current request. If pLocale and nLocale are both 0, then the
13301
+** tokenizer should use its default locale. Otherwise, pLocale points to
13302
+** an nLocale byte buffer containing the name of the locale to use as utf-8
13303
+** text. pLocale is not nul-terminated.
13304
+**
13305
+** FTS5_TOKENIZER
13306
+**
13307
+** There is also an fts5_tokenizer object. This is an older, deprecated,
13308
+** version of fts5_tokenizer_v2. It is similar except that:
13309
+**
13310
+** <ul>
13311
+** <li> There is no "iVersion" field, and
13312
+** <li> The xTokenize() method does not take a locale argument.
13313
+** </ul>
13314
+**
13315
+** Legacy fts5_tokenizer tokenizers must be registered using the
13316
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
13317
+**
13318
+** Tokenizer implementations registered using either API may be retrieved
13319
+** using both xFindTokenizer() and xFindTokenizer_v2().
1324113320
**
1324213321
** SYNONYM SUPPORT
1324313322
**
1324413323
** Custom tokenizers may also support synonyms. Consider a case in which a
1324513324
** user wishes to query for a phrase such as "first place". Using the
@@ -13345,10 +13424,37 @@
1334513424
** provide synonyms when tokenizing document text (method (3)) or query
1334613425
** text (method (2)), not both. Doing so will not cause any errors, but is
1334713426
** inefficient.
1334813427
*/
1334913428
typedef struct Fts5Tokenizer Fts5Tokenizer;
13429
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
13430
+struct fts5_tokenizer_v2 {
13431
+ int iVersion; /* Currently always 2 */
13432
+
13433
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13434
+ void (*xDelete)(Fts5Tokenizer*);
13435
+ int (*xTokenize)(Fts5Tokenizer*,
13436
+ void *pCtx,
13437
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
13438
+ const char *pText, int nText,
13439
+ const char *pLocale, int nLocale,
13440
+ int (*xToken)(
13441
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
13442
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
13443
+ const char *pToken, /* Pointer to buffer containing token */
13444
+ int nToken, /* Size of token in bytes */
13445
+ int iStart, /* Byte offset of token within input text */
13446
+ int iEnd /* Byte offset of end of token within input text */
13447
+ )
13448
+ );
13449
+};
13450
+
13451
+/*
13452
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
13453
+** implementations. The following type is included for legacy applications
13454
+** that still use it.
13455
+*/
1335013456
typedef struct fts5_tokenizer fts5_tokenizer;
1335113457
struct fts5_tokenizer {
1335213458
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
1335313459
void (*xDelete)(Fts5Tokenizer*);
1335413460
int (*xTokenize)(Fts5Tokenizer*,
@@ -13363,10 +13469,11 @@
1336313469
int iStart, /* Byte offset of token within input text */
1336413470
int iEnd /* Byte offset of end of token within input text */
1336513471
)
1336613472
);
1336713473
};
13474
+
1336813475
1336913476
/* Flags that may be passed as the third argument to xTokenize() */
1337013477
#define FTS5_TOKENIZE_QUERY 0x0001
1337113478
#define FTS5_TOKENIZE_PREFIX 0x0002
1337213479
#define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13383,11 +13490,11 @@
1338313490
/*************************************************************************
1338413491
** FTS5 EXTENSION REGISTRATION API
1338513492
*/
1338613493
typedef struct fts5_api fts5_api;
1338713494
struct fts5_api {
13388
- int iVersion; /* Currently always set to 2 */
13495
+ int iVersion; /* Currently always set to 3 */
1338913496
1339013497
/* Create a new tokenizer */
1339113498
int (*xCreateTokenizer)(
1339213499
fts5_api *pApi,
1339313500
const char *zName,
@@ -13410,10 +13517,29 @@
1341013517
const char *zName,
1341113518
void *pUserData,
1341213519
fts5_extension_function xFunction,
1341313520
void (*xDestroy)(void*)
1341413521
);
13522
+
13523
+ /* APIs below this point are only available if iVersion>=3 */
13524
+
13525
+ /* Create a new tokenizer */
13526
+ int (*xCreateTokenizer_v2)(
13527
+ fts5_api *pApi,
13528
+ const char *zName,
13529
+ void *pUserData,
13530
+ fts5_tokenizer_v2 *pTokenizer,
13531
+ void (*xDestroy)(void*)
13532
+ );
13533
+
13534
+ /* Find an existing tokenizer */
13535
+ int (*xFindTokenizer_v2)(
13536
+ fts5_api *pApi,
13537
+ const char *zName,
13538
+ void **ppUserData,
13539
+ fts5_tokenizer_v2 **ppTokenizer
13540
+ );
1341513541
};
1341613542
1341713543
/*
1341813544
** END OF REGISTRATION API
1341913545
*************************************************************************/
1342013546
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -146,11 +146,11 @@
146 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147 ** [sqlite_version()] and [sqlite_source_id()].
148 */
149 #define SQLITE_VERSION "3.47.0"
150 #define SQLITE_VERSION_NUMBER 3047000
151 #define SQLITE_SOURCE_ID "2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9"
152
153 /*
154 ** CAPI3REF: Run-Time Library Version Numbers
155 ** KEYWORDS: sqlite3_version sqlite3_sourceid
156 **
@@ -5613,18 +5613,28 @@
5613 ** might become a no-op if the function is used as term in an
5614 ** [expression index]. On the other hand, SQL functions that never invoke
5615 ** [sqlite3_result_subtype()] should avoid setting this property, as the
5616 ** purpose of this property is to disable certain optimizations that are
5617 ** incompatible with subtypes.
 
 
 
 
 
 
 
 
 
5618 ** </dd>
5619 ** </dl>
5620 */
5621 #define SQLITE_DETERMINISTIC 0x000000800
5622 #define SQLITE_DIRECTONLY 0x000080000
5623 #define SQLITE_SUBTYPE 0x000100000
5624 #define SQLITE_INNOCUOUS 0x000200000
5625 #define SQLITE_RESULT_SUBTYPE 0x001000000
 
5626
5627 /*
5628 ** CAPI3REF: Deprecated Functions
5629 ** DEPRECATED
5630 **
@@ -7425,13 +7435,15 @@
7425 **
7426 ** ^The estimatedRows value is an estimate of the number of rows that
7427 ** will be returned by the strategy.
7428 **
7429 ** The xBestIndex method may optionally populate the idxFlags field with a
7430 ** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
7431 ** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
7432 ** assumes that the strategy may visit at most one row.
 
 
7433 **
7434 ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
7435 ** SQLite also assumes that if a call to the xUpdate() method is made as
7436 ** part of the same statement to delete or update a virtual table row and the
7437 ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7491,11 +7503,13 @@
7491 **
7492 ** Virtual table implementations are allowed to set the
7493 ** [sqlite3_index_info].idxFlags field to some combination of
7494 ** these bits.
7495 */
7496 #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
 
 
7497
7498 /*
7499 ** CAPI3REF: Virtual Table Constraint Operator Codes
7500 **
7501 ** These macros define the allowed values for the
@@ -8328,10 +8342,11 @@
8328 #define SQLITE_TESTCTRL_ALWAYS 13
8329 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
8330 #define SQLITE_TESTCTRL_JSON_SELFCHECK 14
8331 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15
8332 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
 
8333 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
8334 #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
8335 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
8336 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
8337 #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13102,13 +13117,36 @@
13102 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13103 ** includes any embedded 0x00 and trailing data.
13104 **
13105 ** This API can be quite slow if used with an FTS5 table created with the
13106 ** "detail=none" or "detail=column" option.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13107 */
13108 struct Fts5ExtensionApi {
13109 int iVersion; /* Currently always set to 3 */
13110
13111 void *(*xUserData)(Fts5Context*);
13112
13113 int (*xColumnCount)(Fts5Context*);
13114 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13146,10 +13184,19 @@
13146 int (*xQueryToken)(Fts5Context*,
13147 int iPhrase, int iToken,
13148 const char **ppToken, int *pnToken
13149 );
13150 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
 
 
 
 
 
 
 
 
 
13151 };
13152
13153 /*
13154 ** CUSTOM AUXILIARY FUNCTIONS
13155 *************************************************************************/
@@ -13158,19 +13205,20 @@
13158 ** CUSTOM TOKENIZERS
13159 **
13160 ** Applications may also register custom tokenizer types. A tokenizer
13161 ** is registered by providing fts5 with a populated instance of the
13162 ** following structure. All structure methods must be defined, setting
 
13163 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13164 ** behaviour. The structure methods are expected to function as follows:
13165 **
13166 ** xCreate:
13167 ** This function is used to allocate and initialize a tokenizer instance.
13168 ** A tokenizer instance is required to actually tokenize text.
13169 **
13170 ** The first argument passed to this function is a copy of the (void*)
13171 ** pointer provided by the application when the fts5_tokenizer object
13172 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
13173 ** The second and third arguments are an array of nul-terminated strings
13174 ** containing the tokenizer arguments, if any, specified following the
13175 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
13176 ** to create the FTS5 table.
@@ -13190,11 +13238,11 @@
13190 ** This function is expected to tokenize the nText byte string indicated
13191 ** by argument pText. pText may or may not be nul-terminated. The first
13192 ** argument passed to this function is a pointer to an Fts5Tokenizer object
13193 ** returned by an earlier call to xCreate().
13194 **
13195 ** The second argument indicates the reason that FTS5 is requesting
13196 ** tokenization of the supplied text. This is always one of the following
13197 ** four values:
13198 **
13199 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
13200 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -13213,10 +13261,17 @@
13213 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
13214 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
13215 ** function. Or an fts5_api.xColumnSize() request made by the same
13216 ** on a columnsize=0 database.
13217 ** </ul>
 
 
 
 
 
 
 
13218 **
13219 ** For each token in the input string, the supplied callback xToken() must
13220 ** be invoked. The first argument to it should be a copy of the pointer
13221 ** passed as the second argument to xTokenize(). The third and fourth
13222 ** arguments are a pointer to a buffer containing the token text, and the
@@ -13236,10 +13291,34 @@
13236 ** immediately return a copy of the xToken() return value. Or, if the
13237 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
13238 ** if an error occurs with the xTokenize() implementation itself, it
13239 ** may abandon the tokenization and return any error code other than
13240 ** SQLITE_OK or SQLITE_DONE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13241 **
13242 ** SYNONYM SUPPORT
13243 **
13244 ** Custom tokenizers may also support synonyms. Consider a case in which a
13245 ** user wishes to query for a phrase such as "first place". Using the
@@ -13345,10 +13424,37 @@
13345 ** provide synonyms when tokenizing document text (method (3)) or query
13346 ** text (method (2)), not both. Doing so will not cause any errors, but is
13347 ** inefficient.
13348 */
13349 typedef struct Fts5Tokenizer Fts5Tokenizer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13350 typedef struct fts5_tokenizer fts5_tokenizer;
13351 struct fts5_tokenizer {
13352 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13353 void (*xDelete)(Fts5Tokenizer*);
13354 int (*xTokenize)(Fts5Tokenizer*,
@@ -13363,10 +13469,11 @@
13363 int iStart, /* Byte offset of token within input text */
13364 int iEnd /* Byte offset of end of token within input text */
13365 )
13366 );
13367 };
 
13368
13369 /* Flags that may be passed as the third argument to xTokenize() */
13370 #define FTS5_TOKENIZE_QUERY 0x0001
13371 #define FTS5_TOKENIZE_PREFIX 0x0002
13372 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13383,11 +13490,11 @@
13383 /*************************************************************************
13384 ** FTS5 EXTENSION REGISTRATION API
13385 */
13386 typedef struct fts5_api fts5_api;
13387 struct fts5_api {
13388 int iVersion; /* Currently always set to 2 */
13389
13390 /* Create a new tokenizer */
13391 int (*xCreateTokenizer)(
13392 fts5_api *pApi,
13393 const char *zName,
@@ -13410,10 +13517,29 @@
13410 const char *zName,
13411 void *pUserData,
13412 fts5_extension_function xFunction,
13413 void (*xDestroy)(void*)
13414 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13415 };
13416
13417 /*
13418 ** END OF REGISTRATION API
13419 *************************************************************************/
13420
--- extsrc/sqlite3.h
+++ extsrc/sqlite3.h
@@ -146,11 +146,11 @@
146 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
147 ** [sqlite_version()] and [sqlite_source_id()].
148 */
149 #define SQLITE_VERSION "3.47.0"
150 #define SQLITE_VERSION_NUMBER 3047000
151 #define SQLITE_SOURCE_ID "2024-09-02 21:59:31 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c"
152
153 /*
154 ** CAPI3REF: Run-Time Library Version Numbers
155 ** KEYWORDS: sqlite3_version sqlite3_sourceid
156 **
@@ -5613,18 +5613,28 @@
5613 ** might become a no-op if the function is used as term in an
5614 ** [expression index]. On the other hand, SQL functions that never invoke
5615 ** [sqlite3_result_subtype()] should avoid setting this property, as the
5616 ** purpose of this property is to disable certain optimizations that are
5617 ** incompatible with subtypes.
5618 **
5619 ** [[SQLITE_SELFORDER1]] <dt>SQLITE_SELFORDER1</dt><dd>
5620 ** The SQLITE_SELFORDER1 flag indicates that the function is an aggregate
5621 ** that internally orders the values provided to the first argument. The
5622 ** ordered-set aggregate SQL notation with a single ORDER BY term can be
5623 ** used to invoke this function. If the ordered-set aggregate notation is
5624 ** used on a function that lacks this flag, then an error is raised. Note
5625 ** that the ordered-set aggregate syntax is only available if SQLite is
5626 ** built using the -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES compile-time option.
5627 ** </dd>
5628 ** </dl>
5629 */
5630 #define SQLITE_DETERMINISTIC 0x000000800
5631 #define SQLITE_DIRECTONLY 0x000080000
5632 #define SQLITE_SUBTYPE 0x000100000
5633 #define SQLITE_INNOCUOUS 0x000200000
5634 #define SQLITE_RESULT_SUBTYPE 0x001000000
5635 #define SQLITE_SELFORDER1 0x002000000
5636
5637 /*
5638 ** CAPI3REF: Deprecated Functions
5639 ** DEPRECATED
5640 **
@@ -7425,13 +7435,15 @@
7435 **
7436 ** ^The estimatedRows value is an estimate of the number of rows that
7437 ** will be returned by the strategy.
7438 **
7439 ** The xBestIndex method may optionally populate the idxFlags field with a
7440 ** mask of SQLITE_INDEX_SCAN_* flags. One such flag is
7441 ** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN]
7442 ** output to show the idxNum has hex instead of as decimal. Another flag is
7443 ** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will
7444 ** return at most one row.
7445 **
7446 ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
7447 ** SQLite also assumes that if a call to the xUpdate() method is made as
7448 ** part of the same statement to delete or update a virtual table row and the
7449 ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
@@ -7491,11 +7503,13 @@
7503 **
7504 ** Virtual table implementations are allowed to set the
7505 ** [sqlite3_index_info].idxFlags field to some combination of
7506 ** these bits.
7507 */
7508 #define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */
7509 #define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */
7510 /* in EXPLAIN QUERY PLAN */
7511
7512 /*
7513 ** CAPI3REF: Virtual Table Constraint Operator Codes
7514 **
7515 ** These macros define the allowed values for the
@@ -8328,10 +8342,11 @@
8342 #define SQLITE_TESTCTRL_ALWAYS 13
8343 #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
8344 #define SQLITE_TESTCTRL_JSON_SELFCHECK 14
8345 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15
8346 #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
8347 #define SQLITE_TESTCTRL_GETOPT 16
8348 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
8349 #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
8350 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
8351 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
8352 #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -13102,13 +13117,36 @@
13117 ** It is the output of the tokenizer module. For tokendata=1 tables, this
13118 ** includes any embedded 0x00 and trailing data.
13119 **
13120 ** This API can be quite slow if used with an FTS5 table created with the
13121 ** "detail=none" or "detail=column" option.
13122 **
13123 ** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
13124 ** If parameter iCol is less than zero, or greater than or equal to the
13125 ** number of columns in the table, SQLITE_RANGE is returned.
13126 **
13127 ** Otherwise, this function attempts to retrieve the locale associated
13128 ** with column iCol of the current row. Usually, there is no associated
13129 ** locale, and output parameters (*pzLocale) and (*pnLocale) are set
13130 ** to NULL and 0, respectively. However, if the fts5_locale() function
13131 ** was used to associate a locale with the value when it was inserted
13132 ** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
13133 ** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
13134 ** is set to the size in bytes of the buffer, not including the
13135 ** nul-terminator.
13136 **
13137 ** If successful, SQLITE_OK is returned. Or, if an error occurs, an
13138 ** SQLite error code is returned. The final value of the output parameters
13139 ** is undefined in this case.
13140 **
13141 ** xTokenize_v2:
13142 ** Tokenize text using the tokenizer belonging to the FTS5 table. This
13143 ** API is the same as the xTokenize() API, except that it allows a tokenizer
13144 ** locale to be specified.
13145 */
13146 struct Fts5ExtensionApi {
13147 int iVersion; /* Currently always set to 4 */
13148
13149 void *(*xUserData)(Fts5Context*);
13150
13151 int (*xColumnCount)(Fts5Context*);
13152 int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
@@ -13146,10 +13184,19 @@
13184 int (*xQueryToken)(Fts5Context*,
13185 int iPhrase, int iToken,
13186 const char **ppToken, int *pnToken
13187 );
13188 int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
13189
13190 /* Below this point are iVersion>=4 only */
13191 int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
13192 int (*xTokenize_v2)(Fts5Context*,
13193 const char *pText, int nText, /* Text to tokenize */
13194 const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
13195 void *pCtx, /* Context passed to xToken() */
13196 int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
13197 );
13198 };
13199
13200 /*
13201 ** CUSTOM AUXILIARY FUNCTIONS
13202 *************************************************************************/
@@ -13158,19 +13205,20 @@
13205 ** CUSTOM TOKENIZERS
13206 **
13207 ** Applications may also register custom tokenizer types. A tokenizer
13208 ** is registered by providing fts5 with a populated instance of the
13209 ** following structure. All structure methods must be defined, setting
13210 **
13211 ** any member of the fts5_tokenizer struct to NULL leads to undefined
13212 ** behaviour. The structure methods are expected to function as follows:
13213 **
13214 ** xCreate:
13215 ** This function is used to allocate and initialize a tokenizer instance.
13216 ** A tokenizer instance is required to actually tokenize text.
13217 **
13218 ** The first argument passed to this function is a copy of the (void*)
13219 ** pointer provided by the application when the fts5_tokenizer_v2 object
13220 ** was registered with FTS5 (the third argument to xCreateTokenizer()).
13221 ** The second and third arguments are an array of nul-terminated strings
13222 ** containing the tokenizer arguments, if any, specified following the
13223 ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
13224 ** to create the FTS5 table.
@@ -13190,11 +13238,11 @@
13238 ** This function is expected to tokenize the nText byte string indicated
13239 ** by argument pText. pText may or may not be nul-terminated. The first
13240 ** argument passed to this function is a pointer to an Fts5Tokenizer object
13241 ** returned by an earlier call to xCreate().
13242 **
13243 ** The third argument indicates the reason that FTS5 is requesting
13244 ** tokenization of the supplied text. This is always one of the following
13245 ** four values:
13246 **
13247 ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
13248 ** or removed from the FTS table. The tokenizer is being invoked to
@@ -13213,10 +13261,17 @@
13261 ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
13262 ** satisfy an fts5_api.xTokenize() request made by an auxiliary
13263 ** function. Or an fts5_api.xColumnSize() request made by the same
13264 ** on a columnsize=0 database.
13265 ** </ul>
13266 **
13267 ** The sixth and seventh arguments passed to xTokenize() - pLocale and
13268 ** nLocale - are a pointer to a buffer containing the locale to use for
13269 ** tokenization (e.g. "en_US") and its size in bytes, respectively. The
13270 ** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
13271 ** which case nLocale is always 0) to indicate that the tokenizer should
13272 ** use its default locale.
13273 **
13274 ** For each token in the input string, the supplied callback xToken() must
13275 ** be invoked. The first argument to it should be a copy of the pointer
13276 ** passed as the second argument to xTokenize(). The third and fourth
13277 ** arguments are a pointer to a buffer containing the token text, and the
@@ -13236,10 +13291,34 @@
13291 ** immediately return a copy of the xToken() return value. Or, if the
13292 ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
13293 ** if an error occurs with the xTokenize() implementation itself, it
13294 ** may abandon the tokenization and return any error code other than
13295 ** SQLITE_OK or SQLITE_DONE.
13296 **
13297 ** If the tokenizer is registered using an fts5_tokenizer_v2 object,
13298 ** then the xTokenize() method has two additional arguments - pLocale
13299 ** and nLocale. These specify the locale that the tokenizer should use
13300 ** for the current request. If pLocale and nLocale are both 0, then the
13301 ** tokenizer should use its default locale. Otherwise, pLocale points to
13302 ** an nLocale byte buffer containing the name of the locale to use as utf-8
13303 ** text. pLocale is not nul-terminated.
13304 **
13305 ** FTS5_TOKENIZER
13306 **
13307 ** There is also an fts5_tokenizer object. This is an older, deprecated,
13308 ** version of fts5_tokenizer_v2. It is similar except that:
13309 **
13310 ** <ul>
13311 ** <li> There is no "iVersion" field, and
13312 ** <li> The xTokenize() method does not take a locale argument.
13313 ** </ul>
13314 **
13315 ** Legacy fts5_tokenizer tokenizers must be registered using the
13316 ** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
13317 **
13318 ** Tokenizer implementations registered using either API may be retrieved
13319 ** using both xFindTokenizer() and xFindTokenizer_v2().
13320 **
13321 ** SYNONYM SUPPORT
13322 **
13323 ** Custom tokenizers may also support synonyms. Consider a case in which a
13324 ** user wishes to query for a phrase such as "first place". Using the
@@ -13345,10 +13424,37 @@
13424 ** provide synonyms when tokenizing document text (method (3)) or query
13425 ** text (method (2)), not both. Doing so will not cause any errors, but is
13426 ** inefficient.
13427 */
13428 typedef struct Fts5Tokenizer Fts5Tokenizer;
13429 typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
13430 struct fts5_tokenizer_v2 {
13431 int iVersion; /* Currently always 2 */
13432
13433 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13434 void (*xDelete)(Fts5Tokenizer*);
13435 int (*xTokenize)(Fts5Tokenizer*,
13436 void *pCtx,
13437 int flags, /* Mask of FTS5_TOKENIZE_* flags */
13438 const char *pText, int nText,
13439 const char *pLocale, int nLocale,
13440 int (*xToken)(
13441 void *pCtx, /* Copy of 2nd argument to xTokenize() */
13442 int tflags, /* Mask of FTS5_TOKEN_* flags */
13443 const char *pToken, /* Pointer to buffer containing token */
13444 int nToken, /* Size of token in bytes */
13445 int iStart, /* Byte offset of token within input text */
13446 int iEnd /* Byte offset of end of token within input text */
13447 )
13448 );
13449 };
13450
13451 /*
13452 ** New code should use the fts5_tokenizer_v2 type to define tokenizer
13453 ** implementations. The following type is included for legacy applications
13454 ** that still use it.
13455 */
13456 typedef struct fts5_tokenizer fts5_tokenizer;
13457 struct fts5_tokenizer {
13458 int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
13459 void (*xDelete)(Fts5Tokenizer*);
13460 int (*xTokenize)(Fts5Tokenizer*,
@@ -13363,10 +13469,11 @@
13469 int iStart, /* Byte offset of token within input text */
13470 int iEnd /* Byte offset of end of token within input text */
13471 )
13472 );
13473 };
13474
13475
13476 /* Flags that may be passed as the third argument to xTokenize() */
13477 #define FTS5_TOKENIZE_QUERY 0x0001
13478 #define FTS5_TOKENIZE_PREFIX 0x0002
13479 #define FTS5_TOKENIZE_DOCUMENT 0x0004
@@ -13383,11 +13490,11 @@
13490 /*************************************************************************
13491 ** FTS5 EXTENSION REGISTRATION API
13492 */
13493 typedef struct fts5_api fts5_api;
13494 struct fts5_api {
13495 int iVersion; /* Currently always set to 3 */
13496
13497 /* Create a new tokenizer */
13498 int (*xCreateTokenizer)(
13499 fts5_api *pApi,
13500 const char *zName,
@@ -13410,10 +13517,29 @@
13517 const char *zName,
13518 void *pUserData,
13519 fts5_extension_function xFunction,
13520 void (*xDestroy)(void*)
13521 );
13522
13523 /* APIs below this point are only available if iVersion>=3 */
13524
13525 /* Create a new tokenizer */
13526 int (*xCreateTokenizer_v2)(
13527 fts5_api *pApi,
13528 const char *zName,
13529 void *pUserData,
13530 fts5_tokenizer_v2 *pTokenizer,
13531 void (*xDestroy)(void*)
13532 );
13533
13534 /* Find an existing tokenizer */
13535 int (*xFindTokenizer_v2)(
13536 fts5_api *pApi,
13537 const char *zName,
13538 void **ppUserData,
13539 fts5_tokenizer_v2 **ppTokenizer
13540 );
13541 };
13542
13543 /*
13544 ** END OF REGISTRATION API
13545 *************************************************************************/
13546
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -599,5 +599,9 @@
599599
600600
body.branch .brlist > table > tbody > tr:hover:not(.selected),
601601
body.branch .brlist > table > tbody > tr.selected {
602602
background-color: #442800;
603603
}
604
+
605
+p.noMoreShun {
606
+ color: #e5e500;
607
+}
604608
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -599,5 +599,9 @@
599
600 body.branch .brlist > table > tbody > tr:hover:not(.selected),
601 body.branch .brlist > table > tbody > tr.selected {
602 background-color: #442800;
603 }
 
 
 
 
604
--- skins/darkmode/css.txt
+++ skins/darkmode/css.txt
@@ -599,5 +599,9 @@
599
600 body.branch .brlist > table > tbody > tr:hover:not(.selected),
601 body.branch .brlist > table > tbody > tr.selected {
602 background-color: #442800;
603 }
604
605 p.noMoreShun {
606 color: #e5e500;
607 }
608
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -381,11 +381,10 @@
381381
.doc > .content th,
382382
.wiki > .content th {
383383
border-bottom: 1px solid #dee8f2;
384384
padding-bottom: 4px;
385385
padding-right: 6px;
386
- text-align: left;
387386
}
388387
.artifact > .content tr > th,
389388
.dir > .content tr > th,
390389
.doc > .content tr > th,
391390
.wiki > .content tr > th {
@@ -401,10 +400,16 @@
401400
.dir > .content td,
402401
.doc > .content td,
403402
.wiki > .content td {
404403
padding-bottom: 4px;
405404
padding-right: 6px;
405
+}
406
+th {
407
+ /* Special rule at high level to override default centering of table
408
+ header cell text. If it isn't at this level, it can't be
409
+ overridden in the HTML, as by the MD table generator's handling
410
+ of `:` alignment markers. */
406411
text-align: left;
407412
}
408413
409414
/* Wiki adjustments */
410415
pre.verbatim {
411416
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -381,11 +381,10 @@
381 .doc > .content th,
382 .wiki > .content th {
383 border-bottom: 1px solid #dee8f2;
384 padding-bottom: 4px;
385 padding-right: 6px;
386 text-align: left;
387 }
388 .artifact > .content tr > th,
389 .dir > .content tr > th,
390 .doc > .content tr > th,
391 .wiki > .content tr > th {
@@ -401,10 +400,16 @@
401 .dir > .content td,
402 .doc > .content td,
403 .wiki > .content td {
404 padding-bottom: 4px;
405 padding-right: 6px;
 
 
 
 
 
 
406 text-align: left;
407 }
408
409 /* Wiki adjustments */
410 pre.verbatim {
411
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -381,11 +381,10 @@
381 .doc > .content th,
382 .wiki > .content th {
383 border-bottom: 1px solid #dee8f2;
384 padding-bottom: 4px;
385 padding-right: 6px;
 
386 }
387 .artifact > .content tr > th,
388 .dir > .content tr > th,
389 .doc > .content tr > th,
390 .wiki > .content tr > th {
@@ -401,10 +400,16 @@
400 .dir > .content td,
401 .doc > .content td,
402 .wiki > .content td {
403 padding-bottom: 4px;
404 padding-right: 6px;
405 }
406 th {
407 /* Special rule at high level to override default centering of table
408 header cell text. If it isn't at this level, it can't be
409 overridden in the HTML, as by the MD table generator's handling
410 of `:` alignment markers. */
411 text-align: left;
412 }
413
414 /* Wiki adjustments */
415 pre.verbatim {
416
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -452,5 +452,9 @@
452452
453453
body.branch .brlist > table > tbody > tr:hover:not(.selected),
454454
body.branch .brlist > table > tbody > tr.selected {
455455
background-color: #7EA2D9;
456456
}
457
+
458
+p.noMoreShun {
459
+ color: #e5e500;
460
+}
457461
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -452,5 +452,9 @@
452
453 body.branch .brlist > table > tbody > tr:hover:not(.selected),
454 body.branch .brlist > table > tbody > tr.selected {
455 background-color: #7EA2D9;
456 }
 
 
 
 
457
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -452,5 +452,9 @@
452
453 body.branch .brlist > table > tbody > tr:hover:not(.selected),
454 body.branch .brlist > table > tbody > tr.selected {
455 background-color: #7EA2D9;
456 }
457
458 p.noMoreShun {
459 color: #e5e500;
460 }
461
+3 -3
--- src/alerts.c
+++ src/alerts.c
@@ -1649,11 +1649,11 @@
16491649
uSeed = strtoul(P("captchaseed"),0,10);
16501650
zInit = P("captcha");
16511651
}else{
16521652
uSeed = captcha_seed();
16531653
}
1654
- zDecoded = captcha_decode(uSeed);
1654
+ zDecoded = captcha_decode(uSeed, 0);
16551655
zCaptcha = captcha_render(zDecoded);
16561656
@ <tr>
16571657
@ <td class="form_label">Security Code:</td>
16581658
@ <td><input type="text" name="captcha" value="%h(zInit)" size="30">
16591659
captcha_speakit_button(uSeed, "Speak the code");
@@ -2353,11 +2353,11 @@
23532353
if( eErr==1 ){
23542354
@ <td><span class="loginError">&larr; %h(zErr)</span></td>
23552355
}
23562356
@ </tr>
23572357
uSeed = captcha_seed();
2358
- zDecoded = captcha_decode(uSeed);
2358
+ zDecoded = captcha_decode(uSeed, 0);
23592359
zCaptcha = captcha_render(zDecoded);
23602360
@ <tr>
23612361
@ <td class="form_label">Security Code:</td>
23622362
@ <td><input type="text" name="captcha" value="" size="30">
23632363
captcha_speakit_button(uSeed, "Speak the code");
@@ -3356,11 +3356,11 @@
33563356
style_finish_page();
33573357
return;
33583358
}
33593359
if( captcha_needed() ){
33603360
uSeed = captcha_seed();
3361
- zDecoded = captcha_decode(uSeed);
3361
+ zDecoded = captcha_decode(uSeed, 0);
33623362
zCaptcha = captcha_render(zDecoded);
33633363
}
33643364
style_set_current_feature("alerts");
33653365
style_header("Message To Administrator");
33663366
form_begin(0, "%R/contact_admin");
33673367
--- src/alerts.c
+++ src/alerts.c
@@ -1649,11 +1649,11 @@
1649 uSeed = strtoul(P("captchaseed"),0,10);
1650 zInit = P("captcha");
1651 }else{
1652 uSeed = captcha_seed();
1653 }
1654 zDecoded = captcha_decode(uSeed);
1655 zCaptcha = captcha_render(zDecoded);
1656 @ <tr>
1657 @ <td class="form_label">Security Code:</td>
1658 @ <td><input type="text" name="captcha" value="%h(zInit)" size="30">
1659 captcha_speakit_button(uSeed, "Speak the code");
@@ -2353,11 +2353,11 @@
2353 if( eErr==1 ){
2354 @ <td><span class="loginError">&larr; %h(zErr)</span></td>
2355 }
2356 @ </tr>
2357 uSeed = captcha_seed();
2358 zDecoded = captcha_decode(uSeed);
2359 zCaptcha = captcha_render(zDecoded);
2360 @ <tr>
2361 @ <td class="form_label">Security Code:</td>
2362 @ <td><input type="text" name="captcha" value="" size="30">
2363 captcha_speakit_button(uSeed, "Speak the code");
@@ -3356,11 +3356,11 @@
3356 style_finish_page();
3357 return;
3358 }
3359 if( captcha_needed() ){
3360 uSeed = captcha_seed();
3361 zDecoded = captcha_decode(uSeed);
3362 zCaptcha = captcha_render(zDecoded);
3363 }
3364 style_set_current_feature("alerts");
3365 style_header("Message To Administrator");
3366 form_begin(0, "%R/contact_admin");
3367
--- src/alerts.c
+++ src/alerts.c
@@ -1649,11 +1649,11 @@
1649 uSeed = strtoul(P("captchaseed"),0,10);
1650 zInit = P("captcha");
1651 }else{
1652 uSeed = captcha_seed();
1653 }
1654 zDecoded = captcha_decode(uSeed, 0);
1655 zCaptcha = captcha_render(zDecoded);
1656 @ <tr>
1657 @ <td class="form_label">Security Code:</td>
1658 @ <td><input type="text" name="captcha" value="%h(zInit)" size="30">
1659 captcha_speakit_button(uSeed, "Speak the code");
@@ -2353,11 +2353,11 @@
2353 if( eErr==1 ){
2354 @ <td><span class="loginError">&larr; %h(zErr)</span></td>
2355 }
2356 @ </tr>
2357 uSeed = captcha_seed();
2358 zDecoded = captcha_decode(uSeed, 0);
2359 zCaptcha = captcha_render(zDecoded);
2360 @ <tr>
2361 @ <td class="form_label">Security Code:</td>
2362 @ <td><input type="text" name="captcha" value="" size="30">
2363 captcha_speakit_button(uSeed, "Speak the code");
@@ -3356,11 +3356,11 @@
3356 style_finish_page();
3357 return;
3358 }
3359 if( captcha_needed() ){
3360 uSeed = captcha_seed();
3361 zDecoded = captcha_decode(uSeed, 0);
3362 zCaptcha = captcha_render(zDecoded);
3363 }
3364 style_set_current_feature("alerts");
3365 style_header("Message To Administrator");
3366 form_begin(0, "%R/contact_admin");
3367
+3
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125125
*/
126126
int fossil_islower(char c){ return c>='a' && c<='z'; }
127127
int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128128
int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129129
int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
130
+int fossil_isXdigit(char c){
131
+ return (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f');
132
+}
130133
int fossil_tolower(char c){
131134
return fossil_isupper(c) ? c - 'A' + 'a' : c;
132135
}
133136
int fossil_toupper(char c){
134137
return fossil_islower(c) ? c - 'a' + 'A' : c;
135138
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125 */
126 int fossil_islower(char c){ return c>='a' && c<='z'; }
127 int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128 int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129 int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
 
 
 
130 int fossil_tolower(char c){
131 return fossil_isupper(c) ? c - 'A' + 'a' : c;
132 }
133 int fossil_toupper(char c){
134 return fossil_islower(c) ? c - 'a' + 'A' : c;
135
--- src/blob.c
+++ src/blob.c
@@ -125,10 +125,13 @@
125 */
126 int fossil_islower(char c){ return c>='a' && c<='z'; }
127 int fossil_isupper(char c){ return c>='A' && c<='Z'; }
128 int fossil_isdigit(char c){ return c>='0' && c<='9'; }
129 int fossil_isxdigit(char c){ return (c>='0' && c<='9') || (c>='a' && c<='f'); }
130 int fossil_isXdigit(char c){
131 return (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f');
132 }
133 int fossil_tolower(char c){
134 return fossil_isupper(c) ? c - 'A' + 'a' : c;
135 }
136 int fossil_toupper(char c){
137 return fossil_islower(c) ? c - 'a' + 'A' : c;
138
+120 -18
--- src/captcha.c
+++ src/captcha.c
@@ -508,39 +508,122 @@
508508
unsigned int x;
509509
sqlite3_randomness(sizeof(x), &x);
510510
x &= 0x7fffffff;
511511
return x;
512512
}
513
+
514
+/* The SQL that will rotate the the captcha-secret. */
515
+static const char captchaSecretRotationSql[] =
516
+@ SAVEPOINT rotate;
517
+@ DELETE FROM config
518
+@ WHERE name GLOB 'captcha-secret-*'
519
+@ AND mtime<unixepoch('now','-6 hours');
520
+@ UPDATE config
521
+@ SET name=format('captcha-secret-%%d',substr(name,16)+1)
522
+@ WHERE name GLOB 'captcha-secret-*';
523
+@ UPDATE config
524
+@ SET name='captcha-secret-1', mtime=unixepoch()
525
+@ WHERE name='captcha-secret';
526
+@ REPLACE INTO config(name,value,mtime)
527
+@ VALUES('captcha-secret',%Q,unixepoch());
528
+@ RELEASE rotate;
529
+;
530
+
531
+
532
+/*
533
+** Create a new random captcha-secret. Rotate the old one into
534
+** the captcha-secret-N backups. Purge captch-secret-N backups
535
+** older than 6 hours.
536
+**
537
+** Do this on the current database and in all other databases of
538
+** the same login group.
539
+*/
540
+void captcha_secret_rotate(void){
541
+ char *zNew = db_text(0, "SELECT lower(hex(randomblob(20)))");
542
+ char *zSql = mprintf(captchaSecretRotationSql/*works-like:"%Q"*/, zNew);
543
+ char *zErrs = 0;
544
+ fossil_free(zNew);
545
+ db_unprotect(PROTECT_CONFIG);
546
+ db_begin_transaction();
547
+ sqlite3_exec(g.db, zSql, 0, 0, &zErrs);
548
+ db_protect_pop();
549
+ if( zErrs && zErrs[0] ){
550
+ db_rollback_transaction();
551
+ fossil_fatal("Unable to rotate captcha-secret\n%s\nERROR: %s\n",
552
+ zSql, zErrs);
553
+ }
554
+ db_end_transaction(0);
555
+ login_group_sql(zSql, "", "", &zErrs);
556
+ if( zErrs ){
557
+ sqlite3_free(zErrs); /* Silently ignore errors on other repos */
558
+ }
559
+ fossil_free(zSql);
560
+}
561
+
562
+/*
563
+** Return the value of the N-th more recent captcha-secret. The
564
+** most recent captch-secret is 0. Others are prior captcha-secrets
565
+** that have expired, but are retained for a limited period of time
566
+** so that pending anonymous login cookies and/or captcha dialogs
567
+** don't malfunction when the captcha-secret changes.
568
+**
569
+** Clients should start by using the 0-th captcha-secret. Only if
570
+** that one does not work should they advance to 1 and 2 and so forth,
571
+** until this routine returns a NULL pointer.
572
+**
573
+** The value returned is a string obtained from fossil_malloc() and
574
+** should be freed by the caller.
575
+**
576
+** The 0-th captcha secret is the value of Config.Name='captcha-secret'.
577
+** For N>0, the value is in Config.Name='captcha-secret-$N'.
578
+*/
579
+char *captcha_secret(int N){
580
+ if( N==0 ){
581
+ return db_text(0, "SELECT value FROM config WHERE name='captcha-secret'");
582
+ }else{
583
+ return db_text(0,
584
+ "SELECT value FROM config"
585
+ " WHERE name='captcha-secret-%d'"
586
+ " AND mtime>unixepoch('now','-6 hours')", N);
587
+ }
588
+}
513589
514590
/*
515591
** Translate a captcha seed value into the captcha password string.
516592
** The returned string is static and overwritten on each call to
517593
** this function.
594
+**
595
+** Use the N-th captcha secret to compute the password. When N==0,
596
+** a valid password is always returned. A new captcha-secret will
597
+** be created if necessary. But for N>0, the return value might
598
+** be NULL to indicate that there is no N-th captcha-secret.
518599
*/
519
-const char *captcha_decode(unsigned int seed){
520
- const char *zSecret;
600
+const char *captcha_decode(unsigned int seed, int N){
601
+ char *zSecret;
521602
const char *z;
522603
Blob b;
523604
static char zRes[20];
524605
525
- zSecret = db_get("captcha-secret", 0);
606
+ zSecret = captcha_secret(N);
526607
if( zSecret==0 ){
608
+ if( N>0 ) return 0;
527609
db_unprotect(PROTECT_CONFIG);
528610
db_multi_exec(
529611
"REPLACE INTO config(name,value)"
530612
" VALUES('captcha-secret', lower(hex(randomblob(20))));"
531613
);
532614
db_protect_pop();
533
- zSecret = db_get("captcha-secret", 0);
615
+ zSecret = captcha_secret(0);
534616
assert( zSecret!=0 );
535617
}
536618
blob_init(&b, 0, 0);
537619
blob_appendf(&b, "%s-%x", zSecret, seed);
538620
sha1sum_blob(&b, &b);
539621
z = blob_buffer(&b);
540622
memcpy(zRes, z, 8);
541623
zRes[8] = 0;
624
+ fossil_free(zSecret);
542625
return zRes;
543626
}
544627
545628
/*
546629
** Return true if a CAPTCHA is required for editing wiki or tickets or for
@@ -569,26 +652,29 @@
569652
const char *zSeed;
570653
const char *zEntered;
571654
const char *zDecode;
572655
char z[30];
573656
int i;
657
+ int n = 0;
574658
if( !bAlwaysNeeded && !captcha_needed() ){
575659
return 1; /* No captcha needed */
576660
}
577661
zSeed = P("captchaseed");
578662
if( zSeed==0 ) return 0;
579663
zEntered = P("captcha");
580664
if( zEntered==0 || strlen(zEntered)!=8 ) return 0;
581
- zDecode = captcha_decode((unsigned int)atoi(zSeed));
582
- assert( strlen(zDecode)==8 );
583
- for(i=0; i<8; i++){
584
- char c = zEntered[i];
585
- if( c>='A' && c<='F' ) c += 'a' - 'A';
586
- if( c=='O' ) c = '0';
587
- z[i] = c;
588
- }
589
- if( strncmp(zDecode,z,8)!=0 ) return 0;
665
+ do{
666
+ zDecode = captcha_decode((unsigned int)atoi(zSeed), n++);
667
+ if( zDecode==0 ) return 0;
668
+ assert( strlen(zDecode)==8 );
669
+ for(i=0; i<8; i++){
670
+ char c = zEntered[i];
671
+ if( c>='A' && c<='F' ) c += 'a' - 'A';
672
+ if( c=='O' ) c = '0';
673
+ z[i] = c;
674
+ }
675
+ }while( strncmp(zDecode,z,8)!=0 );
590676
return 1;
591677
}
592678
593679
/*
594680
** Generate a captcha display together with the necessary hidden parameter
@@ -607,11 +693,11 @@
607693
const char *zDecoded;
608694
char *zCaptcha;
609695
610696
if( !captcha_needed() && (mFlags & 0x02)==0 ) return;
611697
uSeed = captcha_seed();
612
- zDecoded = captcha_decode(uSeed);
698
+ zDecoded = captcha_decode(uSeed, 0);
613699
zCaptcha = captcha_render(zDecoded);
614700
@ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
615701
@ %h(zCaptcha)
616702
@ </pre>
617703
@ Enter security code shown above:
@@ -656,11 +742,17 @@
656742
const char *zPw = P("name");
657743
if( zPw==0 || zPw[0]==0 ){
658744
(void)exclude_spiders(1);
659745
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
660746
@ to see how HEX would be rendered in the current captcha font.
661
- @ <p>captcha_is_correct(1) returns %d(captcha_is_correct(1)).
747
+ @ <h2>Debug/Testing Values:</h2>
748
+ @ <ul>
749
+ @ <li> g.isHuman = %d(g.isHuman)
750
+ @ <li> g.zLogin = %h(g.zLogin)
751
+ @ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
752
+ @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
753
+ @ </ul>
662754
style_finish_page();
663755
}else{
664756
style_set_current_feature("test");
665757
style_header("Captcha Test");
666758
@ <pre class="captcha">
@@ -683,11 +775,18 @@
683775
**
684776
** If the bTest argument is non-zero, then show the captcha regardless of
685777
** how the agent identifies. This is used for testing only.
686778
*/
687779
int exclude_spiders(int bTest){
688
- if( !bTest && (g.isHuman || g.zLogin!=0) ) return 0;
780
+ if( !bTest ){
781
+ if( g.isHuman ) return 0; /* This user has already proven human */
782
+ if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
783
+ if( login_cookie_wellformed() ){
784
+ /* Logged into another member of the login group */
785
+ return 0;
786
+ }
787
+ }
689788
690789
/* This appears to be a spider. Offer the captcha */
691790
style_set_current_feature("captcha");
692791
style_header("I think you are a robot");
693792
style_submenu_enable(0);
@@ -723,11 +822,14 @@
723822
*/
724823
void captcha_callback(void){
725824
int bTest = atoi(PD("istest","0"));
726825
if( captcha_is_correct(1) ){
727826
if( bTest==0 ){
728
- login_set_anon_cookie(0, 0);
827
+ if( !login_cookie_wellformed() ){
828
+ /* ^^^^--- Don't overwrite a valid login on another repo! */
829
+ login_set_anon_cookie(0, 0);
830
+ }
729831
cgi_append_header("X-Robot: 0\r\n");
730832
}
731833
login_redirect_to_g();
732834
}else{
733835
g.isHuman = 0;
@@ -792,11 +894,11 @@
792894
** Return a WAV file that pronounces the digits of the captcha that
793895
** is determined by the seed given in the name= query parameter.
794896
*/
795897
void captcha_wav_page(void){
796898
const char *zSeed = PD("name","0");
797
- const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
899
+ const char *zDecode = captcha_decode((unsigned int)atoi(zSeed), 0);
798900
Blob audio;
799901
captcha_wav(zDecode, &audio);
800902
cgi_set_content_type("audio/wav");
801903
cgi_set_content(&audio);
802904
}
803905
--- src/captcha.c
+++ src/captcha.c
@@ -508,39 +508,122 @@
508 unsigned int x;
509 sqlite3_randomness(sizeof(x), &x);
510 x &= 0x7fffffff;
511 return x;
512 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
514 /*
515 ** Translate a captcha seed value into the captcha password string.
516 ** The returned string is static and overwritten on each call to
517 ** this function.
 
 
 
 
 
518 */
519 const char *captcha_decode(unsigned int seed){
520 const char *zSecret;
521 const char *z;
522 Blob b;
523 static char zRes[20];
524
525 zSecret = db_get("captcha-secret", 0);
526 if( zSecret==0 ){
 
527 db_unprotect(PROTECT_CONFIG);
528 db_multi_exec(
529 "REPLACE INTO config(name,value)"
530 " VALUES('captcha-secret', lower(hex(randomblob(20))));"
531 );
532 db_protect_pop();
533 zSecret = db_get("captcha-secret", 0);
534 assert( zSecret!=0 );
535 }
536 blob_init(&b, 0, 0);
537 blob_appendf(&b, "%s-%x", zSecret, seed);
538 sha1sum_blob(&b, &b);
539 z = blob_buffer(&b);
540 memcpy(zRes, z, 8);
541 zRes[8] = 0;
 
542 return zRes;
543 }
544
545 /*
546 ** Return true if a CAPTCHA is required for editing wiki or tickets or for
@@ -569,26 +652,29 @@
569 const char *zSeed;
570 const char *zEntered;
571 const char *zDecode;
572 char z[30];
573 int i;
 
574 if( !bAlwaysNeeded && !captcha_needed() ){
575 return 1; /* No captcha needed */
576 }
577 zSeed = P("captchaseed");
578 if( zSeed==0 ) return 0;
579 zEntered = P("captcha");
580 if( zEntered==0 || strlen(zEntered)!=8 ) return 0;
581 zDecode = captcha_decode((unsigned int)atoi(zSeed));
582 assert( strlen(zDecode)==8 );
583 for(i=0; i<8; i++){
584 char c = zEntered[i];
585 if( c>='A' && c<='F' ) c += 'a' - 'A';
586 if( c=='O' ) c = '0';
587 z[i] = c;
588 }
589 if( strncmp(zDecode,z,8)!=0 ) return 0;
 
 
590 return 1;
591 }
592
593 /*
594 ** Generate a captcha display together with the necessary hidden parameter
@@ -607,11 +693,11 @@
607 const char *zDecoded;
608 char *zCaptcha;
609
610 if( !captcha_needed() && (mFlags & 0x02)==0 ) return;
611 uSeed = captcha_seed();
612 zDecoded = captcha_decode(uSeed);
613 zCaptcha = captcha_render(zDecoded);
614 @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
615 @ %h(zCaptcha)
616 @ </pre>
617 @ Enter security code shown above:
@@ -656,11 +742,17 @@
656 const char *zPw = P("name");
657 if( zPw==0 || zPw[0]==0 ){
658 (void)exclude_spiders(1);
659 @ <hr><p>The captcha is shown above. Add a name=HEX query parameter
660 @ to see how HEX would be rendered in the current captcha font.
661 @ <p>captcha_is_correct(1) returns %d(captcha_is_correct(1)).
 
 
 
 
 
 
662 style_finish_page();
663 }else{
664 style_set_current_feature("test");
665 style_header("Captcha Test");
666 @ <pre class="captcha">
@@ -683,11 +775,18 @@
683 **
684 ** If the bTest argument is non-zero, then show the captcha regardless of
685 ** how the agent identifies. This is used for testing only.
686 */
687 int exclude_spiders(int bTest){
688 if( !bTest && (g.isHuman || g.zLogin!=0) ) return 0;
 
 
 
 
 
 
 
689
690 /* This appears to be a spider. Offer the captcha */
691 style_set_current_feature("captcha");
692 style_header("I think you are a robot");
693 style_submenu_enable(0);
@@ -723,11 +822,14 @@
723 */
724 void captcha_callback(void){
725 int bTest = atoi(PD("istest","0"));
726 if( captcha_is_correct(1) ){
727 if( bTest==0 ){
728 login_set_anon_cookie(0, 0);
 
 
 
729 cgi_append_header("X-Robot: 0\r\n");
730 }
731 login_redirect_to_g();
732 }else{
733 g.isHuman = 0;
@@ -792,11 +894,11 @@
792 ** Return a WAV file that pronounces the digits of the captcha that
793 ** is determined by the seed given in the name= query parameter.
794 */
795 void captcha_wav_page(void){
796 const char *zSeed = PD("name","0");
797 const char *zDecode = captcha_decode((unsigned int)atoi(zSeed));
798 Blob audio;
799 captcha_wav(zDecode, &audio);
800 cgi_set_content_type("audio/wav");
801 cgi_set_content(&audio);
802 }
803
--- src/captcha.c
+++ src/captcha.c
@@ -508,39 +508,122 @@
508 unsigned int x;
509 sqlite3_randomness(sizeof(x), &x);
510 x &= 0x7fffffff;
511 return x;
512 }
513
514 /* The SQL that will rotate the the captcha-secret. */
515 static const char captchaSecretRotationSql[] =
516 @ SAVEPOINT rotate;
517 @ DELETE FROM config
518 @ WHERE name GLOB 'captcha-secret-*'
519 @ AND mtime<unixepoch('now','-6 hours');
520 @ UPDATE config
521 @ SET name=format('captcha-secret-%%d',substr(name,16)+1)
522 @ WHERE name GLOB 'captcha-secret-*';
523 @ UPDATE config
524 @ SET name='captcha-secret-1', mtime=unixepoch()
525 @ WHERE name='captcha-secret';
526 @ REPLACE INTO config(name,value,mtime)
527 @ VALUES('captcha-secret',%Q,unixepoch());
528 @ RELEASE rotate;
529 ;
530
531
532 /*
533 ** Create a new random captcha-secret. Rotate the old one into
534 ** the captcha-secret-N backups. Purge captch-secret-N backups
535 ** older than 6 hours.
536 **
537 ** Do this on the current database and in all other databases of
538 ** the same login group.
539 */
540 void captcha_secret_rotate(void){
541 char *zNew = db_text(0, "SELECT lower(hex(randomblob(20)))");
542 char *zSql = mprintf(captchaSecretRotationSql/*works-like:"%Q"*/, zNew);
543 char *zErrs = 0;
544 fossil_free(zNew);
545 db_unprotect(PROTECT_CONFIG);
546 db_begin_transaction();
547 sqlite3_exec(g.db, zSql, 0, 0, &zErrs);
548 db_protect_pop();
549 if( zErrs && zErrs[0] ){
550 db_rollback_transaction();
551 fossil_fatal("Unable to rotate captcha-secret\n%s\nERROR: %s\n",
552 zSql, zErrs);
553 }
554 db_end_transaction(0);
555 login_group_sql(zSql, "", "", &zErrs);
556 if( zErrs ){
557 sqlite3_free(zErrs); /* Silently ignore errors on other repos */
558 }
559 fossil_free(zSql);
560 }
561
562 /*
563 ** Return the value of the N-th more recent captcha-secret. The
564 ** most recent captch-secret is 0. Others are prior captcha-secrets
565 ** that have expired, but are retained for a limited period of time
566 ** so that pending anonymous login cookies and/or captcha dialogs
567 ** don't malfunction when the captcha-secret changes.
568 **
569 ** Clients should start by using the 0-th captcha-secret. Only if
570 ** that one does not work should they advance to 1 and 2 and so forth,
571 ** until this routine returns a NULL pointer.
572 **
573 ** The value returned is a string obtained from fossil_malloc() and
574 ** should be freed by the caller.
575 **
576 ** The 0-th captcha secret is the value of Config.Name='captcha-secret'.
577 ** For N>0, the value is in Config.Name='captcha-secret-$N'.
578 */
579 char *captcha_secret(int N){
580 if( N==0 ){
581 return db_text(0, "SELECT value FROM config WHERE name='captcha-secret'");
582 }else{
583 return db_text(0,
584 "SELECT value FROM config"
585 " WHERE name='captcha-secret-%d'"
586 " AND mtime>unixepoch('now','-6 hours')", N);
587 }
588 }
589
590 /*
591 ** Translate a captcha seed value into the captcha password string.
592 ** The returned string is static and overwritten on each call to
593 ** this function.
594 **
595 ** Use the N-th captcha secret to compute the password. When N==0,
596 ** a valid password is always returned. A new captcha-secret will
597 ** be created if necessary. But for N>0, the return value might
598 ** be NULL to indicate that there is no N-th captcha-secret.
599 */
600 const char *captcha_decode(unsigned int seed, int N){
601 char *zSecret;
602 const char *z;
603 Blob b;
604 static char zRes[20];
605
606 zSecret = captcha_secret(N);
607 if( zSecret==0 ){
608 if( N>0 ) return 0;
609 db_unprotect(PROTECT_CONFIG);
610 db_multi_exec(
611 "REPLACE INTO config(name,value)"
612 " VALUES('captcha-secret', lower(hex(randomblob(20))));"
613 );
614 db_protect_pop();
615 zSecret = captcha_secret(0);
616 assert( zSecret!=0 );
617 }
618 blob_init(&b, 0, 0);
619 blob_appendf(&b, "%s-%x", zSecret, seed);
620 sha1sum_blob(&b, &b);
621 z = blob_buffer(&b);
622 memcpy(zRes, z, 8);
623 zRes[8] = 0;
624 fossil_free(zSecret);
625 return zRes;
626 }
627
628 /*
629 ** Return true if a CAPTCHA is required for editing wiki or tickets or for
@@ -569,26 +652,29 @@
652 const char *zSeed;
653 const char *zEntered;
654 const char *zDecode;
655 char z[30];
656 int i;
657 int n = 0;
658 if( !bAlwaysNeeded && !captcha_needed() ){
659 return 1; /* No captcha needed */
660 }
661 zSeed = P("captchaseed");
662 if( zSeed==0 ) return 0;
663 zEntered = P("captcha");
664 if( zEntered==0 || strlen(zEntered)!=8 ) return 0;
665 do{
666 zDecode = captcha_decode((unsigned int)atoi(zSeed), n++);
667 if( zDecode==0 ) return 0;
668 assert( strlen(zDecode)==8 );
669 for(i=0; i<8; i++){
670 char c = zEntered[i];
671 if( c>='A' && c<='F' ) c += 'a' - 'A';
672 if( c=='O' ) c = '0';
673 z[i] = c;
674 }
675 }while( strncmp(zDecode,z,8)!=0 );
676 return 1;
677 }
678
679 /*
680 ** Generate a captcha display together with the necessary hidden parameter
@@ -607,11 +693,11 @@
693 const char *zDecoded;
694 char *zCaptcha;
695
696 if( !captcha_needed() && (mFlags & 0x02)==0 ) return;
697 uSeed = captcha_seed();
698 zDecoded = captcha_decode(uSeed, 0);
699 zCaptcha = captcha_render(zDecoded);
700 @ <div class="captcha"><table class="captcha"><tr><td><pre class="captcha">
701 @ %h(zCaptcha)
702 @ </pre>
703 @ Enter security code shown above:
@@ -656,11 +742,17 @@
742 const char *zPw = P("name");
743 if( zPw==0 || zPw[0]==0 ){
744 (void)exclude_spiders(1);
745 @ <hr><p>The captcha is shown above. Add a name=HEX query parameter
746 @ to see how HEX would be rendered in the current captcha font.
747 @ <h2>Debug/Testing Values:</h2>
748 @ <ul>
749 @ <li> g.isHuman = %d(g.isHuman)
750 @ <li> g.zLogin = %h(g.zLogin)
751 @ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
752 @ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
753 @ </ul>
754 style_finish_page();
755 }else{
756 style_set_current_feature("test");
757 style_header("Captcha Test");
758 @ <pre class="captcha">
@@ -683,11 +775,18 @@
775 **
776 ** If the bTest argument is non-zero, then show the captcha regardless of
777 ** how the agent identifies. This is used for testing only.
778 */
779 int exclude_spiders(int bTest){
780 if( !bTest ){
781 if( g.isHuman ) return 0; /* This user has already proven human */
782 if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
783 if( login_cookie_wellformed() ){
784 /* Logged into another member of the login group */
785 return 0;
786 }
787 }
788
789 /* This appears to be a spider. Offer the captcha */
790 style_set_current_feature("captcha");
791 style_header("I think you are a robot");
792 style_submenu_enable(0);
@@ -723,11 +822,14 @@
822 */
823 void captcha_callback(void){
824 int bTest = atoi(PD("istest","0"));
825 if( captcha_is_correct(1) ){
826 if( bTest==0 ){
827 if( !login_cookie_wellformed() ){
828 /* ^^^^--- Don't overwrite a valid login on another repo! */
829 login_set_anon_cookie(0, 0);
830 }
831 cgi_append_header("X-Robot: 0\r\n");
832 }
833 login_redirect_to_g();
834 }else{
835 g.isHuman = 0;
@@ -792,11 +894,11 @@
894 ** Return a WAV file that pronounces the digits of the captcha that
895 ** is determined by the seed given in the name= query parameter.
896 */
897 void captcha_wav_page(void){
898 const char *zSeed = PD("name","0");
899 const char *zDecode = captcha_decode((unsigned int)atoi(zSeed), 0);
900 Blob audio;
901 captcha_wav(zDecode, &audio);
902 cgi_set_content_type("audio/wav");
903 cgi_set_content(&audio);
904 }
905
+2 -1
--- src/cgi.c
+++ src/cgi.c
@@ -2122,11 +2122,11 @@
21222122
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
21232123
if( zToken[i] ) zToken[i++] = 0;
21242124
cgi_setenv("PATH_INFO", zToken);
21252125
cgi_setenv("QUERY_STRING", &zToken[i]);
21262126
if( zIpAddr==0 ){
2127
- zIpAddr = cgi_remote_ip(fileno(g.httpIn));
2127
+ zIpAddr = cgi_remote_ip(fossil_fileno(g.httpIn));
21282128
}
21292129
if( zIpAddr ){
21302130
cgi_setenv("REMOTE_ADDR", zIpAddr);
21312131
g.zIpAddr = fossil_strdup(zIpAddr);
21322132
}
@@ -2667,10 +2667,11 @@
26672667
nRequest++;
26682668
}
26692669
close(connection);
26702670
}else{
26712671
int nErr = 0, fd;
2672
+ g.zSockName = 0 /* avoid deleting the socket via atexit() */;
26722673
close(0);
26732674
fd = dup(connection);
26742675
if( fd!=0 ) nErr++;
26752676
close(1);
26762677
fd = dup(connection);
26772678
--- src/cgi.c
+++ src/cgi.c
@@ -2122,11 +2122,11 @@
2122 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
2123 if( zToken[i] ) zToken[i++] = 0;
2124 cgi_setenv("PATH_INFO", zToken);
2125 cgi_setenv("QUERY_STRING", &zToken[i]);
2126 if( zIpAddr==0 ){
2127 zIpAddr = cgi_remote_ip(fileno(g.httpIn));
2128 }
2129 if( zIpAddr ){
2130 cgi_setenv("REMOTE_ADDR", zIpAddr);
2131 g.zIpAddr = fossil_strdup(zIpAddr);
2132 }
@@ -2667,10 +2667,11 @@
2667 nRequest++;
2668 }
2669 close(connection);
2670 }else{
2671 int nErr = 0, fd;
 
2672 close(0);
2673 fd = dup(connection);
2674 if( fd!=0 ) nErr++;
2675 close(1);
2676 fd = dup(connection);
2677
--- src/cgi.c
+++ src/cgi.c
@@ -2122,11 +2122,11 @@
2122 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
2123 if( zToken[i] ) zToken[i++] = 0;
2124 cgi_setenv("PATH_INFO", zToken);
2125 cgi_setenv("QUERY_STRING", &zToken[i]);
2126 if( zIpAddr==0 ){
2127 zIpAddr = cgi_remote_ip(fossil_fileno(g.httpIn));
2128 }
2129 if( zIpAddr ){
2130 cgi_setenv("REMOTE_ADDR", zIpAddr);
2131 g.zIpAddr = fossil_strdup(zIpAddr);
2132 }
@@ -2667,10 +2667,11 @@
2667 nRequest++;
2668 }
2669 close(connection);
2670 }else{
2671 int nErr = 0, fd;
2672 g.zSockName = 0 /* avoid deleting the socket via atexit() */;
2673 close(0);
2674 fd = dup(connection);
2675 if( fd!=0 ) nErr++;
2676 close(1);
2677 fd = dup(connection);
2678
--- src/cookies.c
+++ src/cookies.c
@@ -211,10 +211,19 @@
211211
assert( zPName!=0 );
212212
cookie_parse();
213213
for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214214
return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215215
}
216
+
217
+/* Return the number of characters of hex in the prefix to the
218
+** given string.
219
+*/
220
+static int hex_prefix_length(const char *z){
221
+ int i;
222
+ for(i=0; fossil_isXdigit(z[i]); i++){}
223
+ return i;
224
+}
216225
217226
/*
218227
** WEBPAGE: cookies
219228
**
220229
** Show all cookies associated with Fossil. This shows the text of the
@@ -229,10 +238,11 @@
229238
void cookie_page(void){
230239
int i;
231240
int nCookie = 0;
232241
const char *zName = 0;
233242
const char *zValue = 0;
243
+ const char *zLoginCookie = login_cookie_name();
234244
int isQP = 0;
235245
int bFDSonly = strstr(g.zPath, "fdscookie")!=0;
236246
cookie_parse();
237247
if( bFDSonly ){
238248
style_header("Display Preferences Cookie");
@@ -254,15 +264,32 @@
254264
nCookie++;
255265
@ <li><p><b>%h(zName)</b>: %h(zValue)
256266
@ <input type="submit" name="%h(zDel)" value="Delete">
257267
if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
258268
int j;
269
+ @ <p>This cookie remembers your Fossil display preferences.
259270
@ <ul>
260271
for(j=0; j<cookies.nParam; j++){
261272
@ <li>%h(cookies.aParam[j].zPName): "%h(cookies.aParam[j].zPValue)"
262273
}
263274
@ </ul>
275
+ }else
276
+ if( fossil_strcmp(zName, zLoginCookie)==0 ){
277
+ @ <p>This is your login cookie. If you delete this cookie, you will
278
+ @ be logged out.
279
+ }else
280
+ if( fossil_strncmp(zName, "fossil-", 7)==0
281
+ && strlen(zName)==23
282
+ && hex_prefix_length(&zName[7])==16
283
+ && hex_prefix_length(zValue)>24
284
+ ){
285
+ @ <p>This appears to be a login cookie for another Fossil repository
286
+ @ in the same website.
287
+ }
288
+ else {
289
+ @ <p>This cookie was not generated by Fossil. It might be something
290
+ @ from another program on the same website.
264291
}
265292
fossil_free(zDel);
266293
}
267294
@ </ol>
268295
@ </form>
269296
--- src/cookies.c
+++ src/cookies.c
@@ -211,10 +211,19 @@
211 assert( zPName!=0 );
212 cookie_parse();
213 for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214 return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215 }
 
 
 
 
 
 
 
 
 
216
217 /*
218 ** WEBPAGE: cookies
219 **
220 ** Show all cookies associated with Fossil. This shows the text of the
@@ -229,10 +238,11 @@
229 void cookie_page(void){
230 int i;
231 int nCookie = 0;
232 const char *zName = 0;
233 const char *zValue = 0;
 
234 int isQP = 0;
235 int bFDSonly = strstr(g.zPath, "fdscookie")!=0;
236 cookie_parse();
237 if( bFDSonly ){
238 style_header("Display Preferences Cookie");
@@ -254,15 +264,32 @@
254 nCookie++;
255 @ <li><p><b>%h(zName)</b>: %h(zValue)
256 @ <input type="submit" name="%h(zDel)" value="Delete">
257 if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
258 int j;
 
259 @ <ul>
260 for(j=0; j<cookies.nParam; j++){
261 @ <li>%h(cookies.aParam[j].zPName): "%h(cookies.aParam[j].zPValue)"
262 }
263 @ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264 }
265 fossil_free(zDel);
266 }
267 @ </ol>
268 @ </form>
269
--- src/cookies.c
+++ src/cookies.c
@@ -211,10 +211,19 @@
211 assert( zPName!=0 );
212 cookie_parse();
213 for(i=0; i<cookies.nParam && strcmp(zPName,cookies.aParam[i].zPName); i++){}
214 return i<cookies.nParam ? cookies.aParam[i].zPValue : zDefault;
215 }
216
217 /* Return the number of characters of hex in the prefix to the
218 ** given string.
219 */
220 static int hex_prefix_length(const char *z){
221 int i;
222 for(i=0; fossil_isXdigit(z[i]); i++){}
223 return i;
224 }
225
226 /*
227 ** WEBPAGE: cookies
228 **
229 ** Show all cookies associated with Fossil. This shows the text of the
@@ -229,10 +238,11 @@
238 void cookie_page(void){
239 int i;
240 int nCookie = 0;
241 const char *zName = 0;
242 const char *zValue = 0;
243 const char *zLoginCookie = login_cookie_name();
244 int isQP = 0;
245 int bFDSonly = strstr(g.zPath, "fdscookie")!=0;
246 cookie_parse();
247 if( bFDSonly ){
248 style_header("Display Preferences Cookie");
@@ -254,15 +264,32 @@
264 nCookie++;
265 @ <li><p><b>%h(zName)</b>: %h(zValue)
266 @ <input type="submit" name="%h(zDel)" value="Delete">
267 if( fossil_strcmp(zName, DISPLAY_SETTINGS_COOKIE)==0 && cookies.nParam>0 ){
268 int j;
269 @ <p>This cookie remembers your Fossil display preferences.
270 @ <ul>
271 for(j=0; j<cookies.nParam; j++){
272 @ <li>%h(cookies.aParam[j].zPName): "%h(cookies.aParam[j].zPValue)"
273 }
274 @ </ul>
275 }else
276 if( fossil_strcmp(zName, zLoginCookie)==0 ){
277 @ <p>This is your login cookie. If you delete this cookie, you will
278 @ be logged out.
279 }else
280 if( fossil_strncmp(zName, "fossil-", 7)==0
281 && strlen(zName)==23
282 && hex_prefix_length(&zName[7])==16
283 && hex_prefix_length(zValue)>24
284 ){
285 @ <p>This appears to be a login cookie for another Fossil repository
286 @ in the same website.
287 }
288 else {
289 @ <p>This cookie was not generated by Fossil. It might be something
290 @ from another program on the same website.
291 }
292 fossil_free(zDel);
293 }
294 @ </ol>
295 @ </form>
296
+7 -9
--- src/db.c
+++ src/db.c
@@ -896,11 +896,11 @@
896896
}
897897
int db_column_count(Stmt *pStmt){
898898
return sqlite3_column_count(pStmt->pStmt);
899899
}
900900
char *db_column_malloc(Stmt *pStmt, int N){
901
- return mprintf("%s", db_column_text(pStmt, N));
901
+ return fossil_strdup_nn(db_column_text(pStmt, N));
902902
}
903903
void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
904904
blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
905905
sqlite3_column_bytes(pStmt->pStmt, N));
906906
}
@@ -1192,15 +1192,13 @@
11921192
char *z;
11931193
va_start(ap, zSql);
11941194
db_vprepare(&s, 0, zSql, ap);
11951195
va_end(ap);
11961196
if( db_step(&s)==SQLITE_ROW ){
1197
- z = mprintf("%s", sqlite3_column_text(s.pStmt, 0));
1198
- }else if( zDefault ){
1199
- z = mprintf("%s", zDefault);
1197
+ z = fossil_strdup_nn((const char*)sqlite3_column_text(s.pStmt, 0));
12001198
}else{
1201
- z = 0;
1199
+ z = fossil_strdup(zDefault);
12021200
}
12031201
db_finalize(&s);
12041202
return z;
12051203
}
12061204
@@ -1437,11 +1435,11 @@
14371435
if( sqlite3_user_data(context)==0 ){
14381436
zTemp = obscure((char*)zIn);
14391437
}else{
14401438
zTemp = unobscure((char*)zIn);
14411439
}
1442
- strcpy(zOut, zTemp);
1440
+ fossil_strcpy(zOut, zTemp);
14431441
fossil_free(zTemp);
14441442
sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
14451443
}
14461444
14471445
/*
@@ -2534,11 +2532,11 @@
25342532
if( isValidLocalDb(zPwd) ){
25352533
if( db_open_config(0, 1)==0 ){
25362534
return 0; /* Configuration could not be opened */
25372535
}
25382536
/* Found a valid check-out database file */
2539
- g.zLocalDbName = mprintf("%s", zPwd);
2537
+ g.zLocalDbName = fossil_strdup(zPwd);
25402538
zPwd[n] = 0;
25412539
while( n>0 && zPwd[n-1]=='/' ){
25422540
n--;
25432541
zPwd[n] = 0;
25442542
}
@@ -2670,11 +2668,11 @@
26702668
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
26712669
#endif
26722670
fossil_fatal("not a valid repository: %s", zDbName);
26732671
}
26742672
}
2675
- g.zRepositoryName = mprintf("%s", zDbName);
2673
+ g.zRepositoryName = fossil_strdup(zDbName);
26762674
db_open_or_attach(g.zRepositoryName, "repository");
26772675
g.repositoryOpen = 1;
26782676
sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION,
26792677
&g.iRepoDataVers);
26802678
@@ -3510,11 +3508,11 @@
35103508
zOut = db_text(0, "SELECT content FROM concealed WHERE hash=%Q", zKey);
35113509
}else{
35123510
zOut = 0;
35133511
}
35143512
if( zOut==0 ){
3515
- zOut = mprintf("%s", zKey);
3513
+ zOut = fossil_strdup_nn(zKey);
35163514
}
35173515
return zOut;
35183516
}
35193517
35203518
/*
35213519
--- src/db.c
+++ src/db.c
@@ -896,11 +896,11 @@
896 }
897 int db_column_count(Stmt *pStmt){
898 return sqlite3_column_count(pStmt->pStmt);
899 }
900 char *db_column_malloc(Stmt *pStmt, int N){
901 return mprintf("%s", db_column_text(pStmt, N));
902 }
903 void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
904 blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
905 sqlite3_column_bytes(pStmt->pStmt, N));
906 }
@@ -1192,15 +1192,13 @@
1192 char *z;
1193 va_start(ap, zSql);
1194 db_vprepare(&s, 0, zSql, ap);
1195 va_end(ap);
1196 if( db_step(&s)==SQLITE_ROW ){
1197 z = mprintf("%s", sqlite3_column_text(s.pStmt, 0));
1198 }else if( zDefault ){
1199 z = mprintf("%s", zDefault);
1200 }else{
1201 z = 0;
1202 }
1203 db_finalize(&s);
1204 return z;
1205 }
1206
@@ -1437,11 +1435,11 @@
1437 if( sqlite3_user_data(context)==0 ){
1438 zTemp = obscure((char*)zIn);
1439 }else{
1440 zTemp = unobscure((char*)zIn);
1441 }
1442 strcpy(zOut, zTemp);
1443 fossil_free(zTemp);
1444 sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
1445 }
1446
1447 /*
@@ -2534,11 +2532,11 @@
2534 if( isValidLocalDb(zPwd) ){
2535 if( db_open_config(0, 1)==0 ){
2536 return 0; /* Configuration could not be opened */
2537 }
2538 /* Found a valid check-out database file */
2539 g.zLocalDbName = mprintf("%s", zPwd);
2540 zPwd[n] = 0;
2541 while( n>0 && zPwd[n-1]=='/' ){
2542 n--;
2543 zPwd[n] = 0;
2544 }
@@ -2670,11 +2668,11 @@
2670 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
2671 #endif
2672 fossil_fatal("not a valid repository: %s", zDbName);
2673 }
2674 }
2675 g.zRepositoryName = mprintf("%s", zDbName);
2676 db_open_or_attach(g.zRepositoryName, "repository");
2677 g.repositoryOpen = 1;
2678 sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION,
2679 &g.iRepoDataVers);
2680
@@ -3510,11 +3508,11 @@
3510 zOut = db_text(0, "SELECT content FROM concealed WHERE hash=%Q", zKey);
3511 }else{
3512 zOut = 0;
3513 }
3514 if( zOut==0 ){
3515 zOut = mprintf("%s", zKey);
3516 }
3517 return zOut;
3518 }
3519
3520 /*
3521
--- src/db.c
+++ src/db.c
@@ -896,11 +896,11 @@
896 }
897 int db_column_count(Stmt *pStmt){
898 return sqlite3_column_count(pStmt->pStmt);
899 }
900 char *db_column_malloc(Stmt *pStmt, int N){
901 return fossil_strdup_nn(db_column_text(pStmt, N));
902 }
903 void db_column_blob(Stmt *pStmt, int N, Blob *pBlob){
904 blob_append(pBlob, sqlite3_column_blob(pStmt->pStmt, N),
905 sqlite3_column_bytes(pStmt->pStmt, N));
906 }
@@ -1192,15 +1192,13 @@
1192 char *z;
1193 va_start(ap, zSql);
1194 db_vprepare(&s, 0, zSql, ap);
1195 va_end(ap);
1196 if( db_step(&s)==SQLITE_ROW ){
1197 z = fossil_strdup_nn((const char*)sqlite3_column_text(s.pStmt, 0));
 
 
1198 }else{
1199 z = fossil_strdup(zDefault);
1200 }
1201 db_finalize(&s);
1202 return z;
1203 }
1204
@@ -1437,11 +1435,11 @@
1435 if( sqlite3_user_data(context)==0 ){
1436 zTemp = obscure((char*)zIn);
1437 }else{
1438 zTemp = unobscure((char*)zIn);
1439 }
1440 fossil_strcpy(zOut, zTemp);
1441 fossil_free(zTemp);
1442 sqlite3_result_text(context, zOut, strlen(zOut), sqlite3_free);
1443 }
1444
1445 /*
@@ -2534,11 +2532,11 @@
2532 if( isValidLocalDb(zPwd) ){
2533 if( db_open_config(0, 1)==0 ){
2534 return 0; /* Configuration could not be opened */
2535 }
2536 /* Found a valid check-out database file */
2537 g.zLocalDbName = fossil_strdup(zPwd);
2538 zPwd[n] = 0;
2539 while( n>0 && zPwd[n-1]=='/' ){
2540 n--;
2541 zPwd[n] = 0;
2542 }
@@ -2670,11 +2668,11 @@
2668 g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
2669 #endif
2670 fossil_fatal("not a valid repository: %s", zDbName);
2671 }
2672 }
2673 g.zRepositoryName = fossil_strdup(zDbName);
2674 db_open_or_attach(g.zRepositoryName, "repository");
2675 g.repositoryOpen = 1;
2676 sqlite3_file_control(g.db, "repository", SQLITE_FCNTL_DATA_VERSION,
2677 &g.iRepoDataVers);
2678
@@ -3510,11 +3508,11 @@
3508 zOut = db_text(0, "SELECT content FROM concealed WHERE hash=%Q", zKey);
3509 }else{
3510 zOut = 0;
3511 }
3512 if( zOut==0 ){
3513 zOut = fossil_strdup_nn(zKey);
3514 }
3515 return zOut;
3516 }
3517
3518 /*
3519
+13 -5
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
13111311
.input-with-label {
13121312
border: 1px inset rgba(128, 128, 128, 0.5);
13131313
border-radius: 0.25em;
13141314
padding: 0.1em;
13151315
margin: 0 0.5em;
1316
- display: inline-block;
1316
+ display: inline-block
1317
+ /* We would really like flex layout but changing that
1318
+ currently introduces a good deal of UI breakage
1319
+ to chase down. The advantage would be better alignment
1320
+ of the contained elements. */;
13171321
cursor: default;
13181322
white-space: nowrap;
1323
+}
1324
+.submenu .input-with-label {
1325
+ border: none;
13191326
}
13201327
.input-with-label > * {
13211328
vertical-align: middle;
13221329
}
13231330
.input-with-label > label {
13241331
display: inline; /* some skins set label display to block! */
13251332
cursor: pointer;
1333
+ white-space: nowrap;
13261334
}
13271335
.input-with-label > input {
13281336
margin: 0;
13291337
}
13301338
.input-with-label > button {
@@ -1764,14 +1772,14 @@
17641772
div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
17651773
table.numbered-lines > tbody > tr,
17661774
tr.diffskip > td.chunkctrl,
17671775
#fossil-status-bar,
17681776
.monospace {
1769
- font-family: Source Code Pro, Menlo, Monaco, Consolas,
1770
- Andale Mono, Ubuntu Mono, Deja Vu Sans Mono,
1771
- Letter Gothic, Letter Gothic Std, Prestige Elite Std,
1772
- Courier, Courier New,
1777
+ font-family: "Source Code Pro", "Menlo", "Monaco", "Consolas",
1778
+ "Andale Mono", "Ubuntu Mono", "Deja Vu Sans Mono",
1779
+ "Letter Gothic", "Letter Gothic Std", "Prestige Elite Std",
1780
+ "Courier", "Courier New",
17731781
monospace;
17741782
}
17751783
17761784
div.markdown > ol.footnotes {
17771785
font-size: 90%;
17781786
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
1311 .input-with-label {
1312 border: 1px inset rgba(128, 128, 128, 0.5);
1313 border-radius: 0.25em;
1314 padding: 0.1em;
1315 margin: 0 0.5em;
1316 display: inline-block;
 
 
 
 
1317 cursor: default;
1318 white-space: nowrap;
 
 
 
1319 }
1320 .input-with-label > * {
1321 vertical-align: middle;
1322 }
1323 .input-with-label > label {
1324 display: inline; /* some skins set label display to block! */
1325 cursor: pointer;
 
1326 }
1327 .input-with-label > input {
1328 margin: 0;
1329 }
1330 .input-with-label > button {
@@ -1764,14 +1772,14 @@
1764 div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
1765 table.numbered-lines > tbody > tr,
1766 tr.diffskip > td.chunkctrl,
1767 #fossil-status-bar,
1768 .monospace {
1769 font-family: Source Code Pro, Menlo, Monaco, Consolas,
1770 Andale Mono, Ubuntu Mono, Deja Vu Sans Mono,
1771 Letter Gothic, Letter Gothic Std, Prestige Elite Std,
1772 Courier, Courier New,
1773 monospace;
1774 }
1775
1776 div.markdown > ol.footnotes {
1777 font-size: 90%;
1778
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
1311 .input-with-label {
1312 border: 1px inset rgba(128, 128, 128, 0.5);
1313 border-radius: 0.25em;
1314 padding: 0.1em;
1315 margin: 0 0.5em;
1316 display: inline-block
1317 /* We would really like flex layout but changing that
1318 currently introduces a good deal of UI breakage
1319 to chase down. The advantage would be better alignment
1320 of the contained elements. */;
1321 cursor: default;
1322 white-space: nowrap;
1323 }
1324 .submenu .input-with-label {
1325 border: none;
1326 }
1327 .input-with-label > * {
1328 vertical-align: middle;
1329 }
1330 .input-with-label > label {
1331 display: inline; /* some skins set label display to block! */
1332 cursor: pointer;
1333 white-space: nowrap;
1334 }
1335 .input-with-label > input {
1336 margin: 0;
1337 }
1338 .input-with-label > button {
@@ -1764,14 +1772,14 @@
1772 div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
1773 table.numbered-lines > tbody > tr,
1774 tr.diffskip > td.chunkctrl,
1775 #fossil-status-bar,
1776 .monospace {
1777 font-family: "Source Code Pro", "Menlo", "Monaco", "Consolas",
1778 "Andale Mono", "Ubuntu Mono", "Deja Vu Sans Mono",
1779 "Letter Gothic", "Letter Gothic Std", "Prestige Elite Std",
1780 "Courier", "Courier New",
1781 monospace;
1782 }
1783
1784 div.markdown > ol.footnotes {
1785 font-size: 90%;
1786
+13 -5
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
13111311
.input-with-label {
13121312
border: 1px inset rgba(128, 128, 128, 0.5);
13131313
border-radius: 0.25em;
13141314
padding: 0.1em;
13151315
margin: 0 0.5em;
1316
- display: inline-block;
1316
+ display: inline-block
1317
+ /* We would really like flex layout but changing that
1318
+ currently introduces a good deal of UI breakage
1319
+ to chase down. The advantage would be better alignment
1320
+ of the contained elements. */;
13171321
cursor: default;
13181322
white-space: nowrap;
1323
+}
1324
+.submenu .input-with-label {
1325
+ border: none;
13191326
}
13201327
.input-with-label > * {
13211328
vertical-align: middle;
13221329
}
13231330
.input-with-label > label {
13241331
display: inline; /* some skins set label display to block! */
13251332
cursor: pointer;
1333
+ white-space: nowrap;
13261334
}
13271335
.input-with-label > input {
13281336
margin: 0;
13291337
}
13301338
.input-with-label > button {
@@ -1764,14 +1772,14 @@
17641772
div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
17651773
table.numbered-lines > tbody > tr,
17661774
tr.diffskip > td.chunkctrl,
17671775
#fossil-status-bar,
17681776
.monospace {
1769
- font-family: Source Code Pro, Menlo, Monaco, Consolas,
1770
- Andale Mono, Ubuntu Mono, Deja Vu Sans Mono,
1771
- Letter Gothic, Letter Gothic Std, Prestige Elite Std,
1772
- Courier, Courier New,
1777
+ font-family: "Source Code Pro", "Menlo", "Monaco", "Consolas",
1778
+ "Andale Mono", "Ubuntu Mono", "Deja Vu Sans Mono",
1779
+ "Letter Gothic", "Letter Gothic Std", "Prestige Elite Std",
1780
+ "Courier", "Courier New",
17731781
monospace;
17741782
}
17751783
17761784
div.markdown > ol.footnotes {
17771785
font-size: 90%;
17781786
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
1311 .input-with-label {
1312 border: 1px inset rgba(128, 128, 128, 0.5);
1313 border-radius: 0.25em;
1314 padding: 0.1em;
1315 margin: 0 0.5em;
1316 display: inline-block;
 
 
 
 
1317 cursor: default;
1318 white-space: nowrap;
 
 
 
1319 }
1320 .input-with-label > * {
1321 vertical-align: middle;
1322 }
1323 .input-with-label > label {
1324 display: inline; /* some skins set label display to block! */
1325 cursor: pointer;
 
1326 }
1327 .input-with-label > input {
1328 margin: 0;
1329 }
1330 .input-with-label > button {
@@ -1764,14 +1772,14 @@
1764 div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
1765 table.numbered-lines > tbody > tr,
1766 tr.diffskip > td.chunkctrl,
1767 #fossil-status-bar,
1768 .monospace {
1769 font-family: Source Code Pro, Menlo, Monaco, Consolas,
1770 Andale Mono, Ubuntu Mono, Deja Vu Sans Mono,
1771 Letter Gothic, Letter Gothic Std, Prestige Elite Std,
1772 Courier, Courier New,
1773 monospace;
1774 }
1775
1776 div.markdown > ol.footnotes {
1777 font-size: 90%;
1778
--- src/default.css
+++ src/default.css
@@ -1311,20 +1311,28 @@
1311 .input-with-label {
1312 border: 1px inset rgba(128, 128, 128, 0.5);
1313 border-radius: 0.25em;
1314 padding: 0.1em;
1315 margin: 0 0.5em;
1316 display: inline-block
1317 /* We would really like flex layout but changing that
1318 currently introduces a good deal of UI breakage
1319 to chase down. The advantage would be better alignment
1320 of the contained elements. */;
1321 cursor: default;
1322 white-space: nowrap;
1323 }
1324 .submenu .input-with-label {
1325 border: none;
1326 }
1327 .input-with-label > * {
1328 vertical-align: middle;
1329 }
1330 .input-with-label > label {
1331 display: inline; /* some skins set label display to block! */
1332 cursor: pointer;
1333 white-space: nowrap;
1334 }
1335 .input-with-label > input {
1336 margin: 0;
1337 }
1338 .input-with-label > button {
@@ -1764,14 +1772,14 @@
1772 div.markdown ol.footnotes > li.fn-joined > sup.fn-joined,
1773 table.numbered-lines > tbody > tr,
1774 tr.diffskip > td.chunkctrl,
1775 #fossil-status-bar,
1776 .monospace {
1777 font-family: "Source Code Pro", "Menlo", "Monaco", "Consolas",
1778 "Andale Mono", "Ubuntu Mono", "Deja Vu Sans Mono",
1779 "Letter Gothic", "Letter Gothic Std", "Prestige Elite Std",
1780 "Courier", "Courier New",
1781 monospace;
1782 }
1783
1784 div.markdown > ol.footnotes {
1785 font-size: 90%;
1786
--- src/descendants.c
+++ src/descendants.c
@@ -247,11 +247,11 @@
247247
" AND event.objid=plink.pid"
248248
" ORDER BY mtime DESC"
249249
" )"
250250
" SELECT ancestor.rid FROM ancestor"
251251
" WHERE EXISTS(SELECT 1 FROM tagxref"
252
- " WHERE tagid=%d AND tagxref.rid=+ancestor.rid"
252
+ " WHERE tagid=%d AND tagxref.rid=ancestor.rid"
253253
" AND value=%Q AND tagtype>0)"
254254
" ORDER BY mtime DESC"
255255
" LIMIT 1",
256256
rid, rid, TAG_BRANCH, zBranch
257257
);
258258
--- src/descendants.c
+++ src/descendants.c
@@ -247,11 +247,11 @@
247 " AND event.objid=plink.pid"
248 " ORDER BY mtime DESC"
249 " )"
250 " SELECT ancestor.rid FROM ancestor"
251 " WHERE EXISTS(SELECT 1 FROM tagxref"
252 " WHERE tagid=%d AND tagxref.rid=+ancestor.rid"
253 " AND value=%Q AND tagtype>0)"
254 " ORDER BY mtime DESC"
255 " LIMIT 1",
256 rid, rid, TAG_BRANCH, zBranch
257 );
258
--- src/descendants.c
+++ src/descendants.c
@@ -247,11 +247,11 @@
247 " AND event.objid=plink.pid"
248 " ORDER BY mtime DESC"
249 " )"
250 " SELECT ancestor.rid FROM ancestor"
251 " WHERE EXISTS(SELECT 1 FROM tagxref"
252 " WHERE tagid=%d AND tagxref.rid=ancestor.rid"
253 " AND value=%Q AND tagtype>0)"
254 " ORDER BY mtime DESC"
255 " LIMIT 1",
256 rid, rid, TAG_BRANCH, zBranch
257 );
258
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137137
repoUrl( repoRelativePath [,urlParams] )
138138
139139
Creates a URL by prepending this.rootPath to the given path
140140
(which must be relative from the top of the site, without a
141141
leading slash). If urlParams is a string, it must be
142
- paramters encoded in the form "key=val&key2=val2..." WITHOUT
142
+ parameters encoded in the form "key=val&key2=val2..." WITHOUT
143143
a leading '?'. If it's an object, all of its properties get
144144
appended to the URL in that form.
145145
*/
146146
F.repoUrl = function(path,urlParams){
147147
if(!urlParams) return this.rootPath+path;
@@ -300,25 +300,25 @@
300300
301301
If passed only 1 argument, or passed a falsy 2nd argument,
302302
the default wait time set in this function's $defaultDelay
303303
property is used.
304304
305
- Source: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
305
+ Inspiration: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
306306
*/
307
- F.debounce = function f(func, wait, immediate) {
308
- var timeout;
309
- if(!wait) wait = f.$defaultDelay;
307
+ F.debounce = function f(func, waitMs, immediate) {
308
+ var timeoutId;
309
+ if(!waitMs) waitMs = f.$defaultDelay;
310310
return function() {
311311
const context = this, args = Array.prototype.slice.call(arguments);
312312
const later = function() {
313
- timeout = undefined;
313
+ timeoutId = undefined;
314314
if(!immediate) func.apply(context, args);
315315
};
316
- const callNow = immediate && !timeout;
317
- clearTimeout(timeout);
318
- timeout = setTimeout(later, wait);
316
+ const callNow = immediate && !timeoutId;
317
+ clearTimeout(timeoutId);
318
+ timeoutId = setTimeout(later, waitMs);
319319
if(callNow) func.apply(context, args);
320320
};
321321
};
322322
F.debounce.$defaultDelay = 500 /*arbitrary*/;
323323
324324
})(window);
325325
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137 repoUrl( repoRelativePath [,urlParams] )
138
139 Creates a URL by prepending this.rootPath to the given path
140 (which must be relative from the top of the site, without a
141 leading slash). If urlParams is a string, it must be
142 paramters encoded in the form "key=val&key2=val2..." WITHOUT
143 a leading '?'. If it's an object, all of its properties get
144 appended to the URL in that form.
145 */
146 F.repoUrl = function(path,urlParams){
147 if(!urlParams) return this.rootPath+path;
@@ -300,25 +300,25 @@
300
301 If passed only 1 argument, or passed a falsy 2nd argument,
302 the default wait time set in this function's $defaultDelay
303 property is used.
304
305 Source: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
306 */
307 F.debounce = function f(func, wait, immediate) {
308 var timeout;
309 if(!wait) wait = f.$defaultDelay;
310 return function() {
311 const context = this, args = Array.prototype.slice.call(arguments);
312 const later = function() {
313 timeout = undefined;
314 if(!immediate) func.apply(context, args);
315 };
316 const callNow = immediate && !timeout;
317 clearTimeout(timeout);
318 timeout = setTimeout(later, wait);
319 if(callNow) func.apply(context, args);
320 };
321 };
322 F.debounce.$defaultDelay = 500 /*arbitrary*/;
323
324 })(window);
325
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137 repoUrl( repoRelativePath [,urlParams] )
138
139 Creates a URL by prepending this.rootPath to the given path
140 (which must be relative from the top of the site, without a
141 leading slash). If urlParams is a string, it must be
142 parameters encoded in the form "key=val&key2=val2..." WITHOUT
143 a leading '?'. If it's an object, all of its properties get
144 appended to the URL in that form.
145 */
146 F.repoUrl = function(path,urlParams){
147 if(!urlParams) return this.rootPath+path;
@@ -300,25 +300,25 @@
300
301 If passed only 1 argument, or passed a falsy 2nd argument,
302 the default wait time set in this function's $defaultDelay
303 property is used.
304
305 Inspiration: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
306 */
307 F.debounce = function f(func, waitMs, immediate) {
308 var timeoutId;
309 if(!waitMs) waitMs = f.$defaultDelay;
310 return function() {
311 const context = this, args = Array.prototype.slice.call(arguments);
312 const later = function() {
313 timeoutId = undefined;
314 if(!immediate) func.apply(context, args);
315 };
316 const callNow = immediate && !timeoutId;
317 clearTimeout(timeoutId);
318 timeoutId = setTimeout(later, waitMs);
319 if(callNow) func.apply(context, args);
320 };
321 };
322 F.debounce.$defaultDelay = 500 /*arbitrary*/;
323
324 })(window);
325
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1245,10 +1245,11 @@
12451245
self.finfo.checkin,
12461246
"]</code> &rarr; Local Edits</div>",
12471247
c||'No changes.'
12481248
].join(''));
12491249
F.diff.setupDiffContextLoad();
1250
+ if(sbs) P.tweakSbsDiffs();
12501251
F.message('Updated diff.');
12511252
self.tabs.switchToTab(self.e.tabs.diff);
12521253
}
12531254
});
12541255
return this;
12551256
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1245,10 +1245,11 @@
1245 self.finfo.checkin,
1246 "]</code> &rarr; Local Edits</div>",
1247 c||'No changes.'
1248 ].join(''));
1249 F.diff.setupDiffContextLoad();
 
1250 F.message('Updated diff.');
1251 self.tabs.switchToTab(self.e.tabs.diff);
1252 }
1253 });
1254 return this;
1255
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -1245,10 +1245,11 @@
1245 self.finfo.checkin,
1246 "]</code> &rarr; Local Edits</div>",
1247 c||'No changes.'
1248 ].join(''));
1249 F.diff.setupDiffContextLoad();
1250 if(sbs) P.tweakSbsDiffs();
1251 F.message('Updated diff.');
1252 self.tabs.switchToTab(self.e.tabs.diff);
1253 }
1254 });
1255 return this;
1256
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1545,10 +1545,11 @@
15451545
self.winfo.name,
15461546
"]</code> &rarr; Local Edits</div>",
15471547
c||'No changes.'
15481548
].join(''));
15491549
F.diff.setupDiffContextLoad();
1550
+ if(sbs) P.tweakSbsDiffs();
15501551
F.message('Updated diff.');
15511552
self.tabs.switchToTab(self.e.tabs.diff);
15521553
}
15531554
});
15541555
return this;
15551556
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1545,10 +1545,11 @@
1545 self.winfo.name,
1546 "]</code> &rarr; Local Edits</div>",
1547 c||'No changes.'
1548 ].join(''));
1549 F.diff.setupDiffContextLoad();
 
1550 F.message('Updated diff.');
1551 self.tabs.switchToTab(self.e.tabs.diff);
1552 }
1553 });
1554 return this;
1555
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -1545,10 +1545,11 @@
1545 self.winfo.name,
1546 "]</code> &rarr; Local Edits</div>",
1547 c||'No changes.'
1548 ].join(''));
1549 F.diff.setupDiffContextLoad();
1550 if(sbs) P.tweakSbsDiffs();
1551 F.message('Updated diff.');
1552 self.tabs.switchToTab(self.e.tabs.diff);
1553 }
1554 });
1555 return this;
1556
+1 -7
--- src/http.c
+++ src/http.c
@@ -21,16 +21,10 @@
2121
#include "http.h"
2222
#include <assert.h>
2323
2424
#ifdef _WIN32
2525
#include <io.h>
26
-#ifndef isatty
27
-#define isatty(d) _isatty(d)
28
-#endif
29
-#ifndef fileno
30
-#define fileno(s) _fileno(s)
31
-#endif
3226
#endif
3327
3428
3529
#if INTERFACE
3630
/*
@@ -206,11 +200,11 @@
206200
Blob x;
207201
char *zUser;
208202
char *zPw;
209203
char *zPrompt;
210204
char *zHttpAuth = 0;
211
- if( !isatty(fileno(stdin)) ) return 0;
205
+ if( !fossil_isatty(fossil_fileno(stdin)) ) return 0;
212206
zPrompt = mprintf("\n%s authorization required by\n%s\n",
213207
g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
214208
fossil_print("%s", zPrompt);
215209
free(zPrompt);
216210
if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
217211
--- src/http.c
+++ src/http.c
@@ -21,16 +21,10 @@
21 #include "http.h"
22 #include <assert.h>
23
24 #ifdef _WIN32
25 #include <io.h>
26 #ifndef isatty
27 #define isatty(d) _isatty(d)
28 #endif
29 #ifndef fileno
30 #define fileno(s) _fileno(s)
31 #endif
32 #endif
33
34
35 #if INTERFACE
36 /*
@@ -206,11 +200,11 @@
206 Blob x;
207 char *zUser;
208 char *zPw;
209 char *zPrompt;
210 char *zHttpAuth = 0;
211 if( !isatty(fileno(stdin)) ) return 0;
212 zPrompt = mprintf("\n%s authorization required by\n%s\n",
213 g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
214 fossil_print("%s", zPrompt);
215 free(zPrompt);
216 if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
217
--- src/http.c
+++ src/http.c
@@ -21,16 +21,10 @@
21 #include "http.h"
22 #include <assert.h>
23
24 #ifdef _WIN32
25 #include <io.h>
 
 
 
 
 
 
26 #endif
27
28
29 #if INTERFACE
30 /*
@@ -206,11 +200,11 @@
200 Blob x;
201 char *zUser;
202 char *zPw;
203 char *zPrompt;
204 char *zHttpAuth = 0;
205 if( !fossil_isatty(fossil_fileno(stdin)) ) return 0;
206 zPrompt = mprintf("\n%s authorization required by\n%s\n",
207 g.url.isHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.url.canonical);
208 fossil_print("%s", zPrompt);
209 free(zPrompt);
210 if ( g.url.user && g.url.passwd && use_fossil_creds_for_httpauth_prompt() ){
211
-22
--- src/import.c
+++ src/import.c
@@ -73,32 +73,10 @@
7373
ImportFile *pInlineFile; /* File marked "inline" */
7474
int fromLoaded; /* True zFrom content loaded into aFile[] */
7575
int tagCommit; /* True if the commit adds a tag */
7676
} gg;
7777
78
-/*
79
-** Duplicate a string.
80
-*/
81
-char *fossil_strndup(const char *zOrig, int len){
82
- char *z = 0;
83
- if( zOrig ){
84
- int n;
85
- if( len<0 ){
86
- n = strlen(zOrig);
87
- }else{
88
- for( n=0; zOrig[n] && n<len; ++n );
89
- }
90
- z = fossil_malloc( n+1 );
91
- memcpy(z, zOrig, n);
92
- z[n] = 0;
93
- }
94
- return z;
95
-}
96
-char *fossil_strdup(const char *zOrig){
97
- return fossil_strndup(zOrig, -1);
98
-}
99
-
10078
/*
10179
** A no-op "xFinish" method
10280
*/
10381
static void finish_noop(void){}
10482
10583
--- src/import.c
+++ src/import.c
@@ -73,32 +73,10 @@
73 ImportFile *pInlineFile; /* File marked "inline" */
74 int fromLoaded; /* True zFrom content loaded into aFile[] */
75 int tagCommit; /* True if the commit adds a tag */
76 } gg;
77
78 /*
79 ** Duplicate a string.
80 */
81 char *fossil_strndup(const char *zOrig, int len){
82 char *z = 0;
83 if( zOrig ){
84 int n;
85 if( len<0 ){
86 n = strlen(zOrig);
87 }else{
88 for( n=0; zOrig[n] && n<len; ++n );
89 }
90 z = fossil_malloc( n+1 );
91 memcpy(z, zOrig, n);
92 z[n] = 0;
93 }
94 return z;
95 }
96 char *fossil_strdup(const char *zOrig){
97 return fossil_strndup(zOrig, -1);
98 }
99
100 /*
101 ** A no-op "xFinish" method
102 */
103 static void finish_noop(void){}
104
105
--- src/import.c
+++ src/import.c
@@ -73,32 +73,10 @@
73 ImportFile *pInlineFile; /* File marked "inline" */
74 int fromLoaded; /* True zFrom content loaded into aFile[] */
75 int tagCommit; /* True if the commit adds a tag */
76 } gg;
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78 /*
79 ** A no-op "xFinish" method
80 */
81 static void finish_noop(void){}
82
83
+2 -1
--- src/info.c
+++ src/info.c
@@ -891,11 +891,12 @@
891891
"<div class=\"section accordion\">References</div>\n");
892892
@ <div class="section accordion">Context</div><div class="accordion_panel">
893893
render_checkin_context(rid, 0, 0, 0);
894894
@ </div><div class="section accordion">Changes</div>
895895
@ <div class="accordion_panel">
896
- @ <div class="sectionmenu">
896
+ @ <div class="sectionmenu info-changes-menu">
897
+ /* ^^^ .info-changes-menu is used by diff scroll sync */
897898
pCfg = construct_diff_flags(diffType, &DCfg);
898899
DCfg.pRe = pRe;
899900
zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
900901
if( diffType!=0 ){
901902
@ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
902903
--- src/info.c
+++ src/info.c
@@ -891,11 +891,12 @@
891 "<div class=\"section accordion\">References</div>\n");
892 @ <div class="section accordion">Context</div><div class="accordion_panel">
893 render_checkin_context(rid, 0, 0, 0);
894 @ </div><div class="section accordion">Changes</div>
895 @ <div class="accordion_panel">
896 @ <div class="sectionmenu">
 
897 pCfg = construct_diff_flags(diffType, &DCfg);
898 DCfg.pRe = pRe;
899 zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
900 if( diffType!=0 ){
901 @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
902
--- src/info.c
+++ src/info.c
@@ -891,11 +891,12 @@
891 "<div class=\"section accordion\">References</div>\n");
892 @ <div class="section accordion">Context</div><div class="accordion_panel">
893 render_checkin_context(rid, 0, 0, 0);
894 @ </div><div class="section accordion">Changes</div>
895 @ <div class="accordion_panel">
896 @ <div class="sectionmenu info-changes-menu">
897 /* ^^^ .info-changes-menu is used by diff scroll sync */
898 pCfg = construct_diff_flags(diffType, &DCfg);
899 DCfg.pRe = pRe;
900 zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
901 if( diffType!=0 ){
902 @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
903
+2 -2
--- src/json.c
+++ src/json.c
@@ -221,14 +221,14 @@
221221
** when constructing the JSON response envelope, so the static buffer
222222
** "shouldn't" be a problem.
223223
**
224224
*/
225225
char const * json_rc_cstr( int code ){
226
- enum { BufSize = 12 };
226
+ enum { BufSize = 13 };
227227
static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
228228
assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
229
- sprintf(buf+7,"%04d", code);
229
+ sqlite3_snprintf((int)BufSize, buf+7,"%04d", code);
230230
return buf;
231231
}
232232
233233
/*
234234
** Adds v to the API-internal cleanup mechanism. key is ignored
235235
--- src/json.c
+++ src/json.c
@@ -221,14 +221,14 @@
221 ** when constructing the JSON response envelope, so the static buffer
222 ** "shouldn't" be a problem.
223 **
224 */
225 char const * json_rc_cstr( int code ){
226 enum { BufSize = 12 };
227 static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
228 assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
229 sprintf(buf+7,"%04d", code);
230 return buf;
231 }
232
233 /*
234 ** Adds v to the API-internal cleanup mechanism. key is ignored
235
--- src/json.c
+++ src/json.c
@@ -221,14 +221,14 @@
221 ** when constructing the JSON response envelope, so the static buffer
222 ** "shouldn't" be a problem.
223 **
224 */
225 char const * json_rc_cstr( int code ){
226 enum { BufSize = 13 };
227 static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
228 assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
229 sqlite3_snprintf((int)BufSize, buf+7,"%04d", code);
230 return buf;
231 }
232
233 /*
234 ** Adds v to the API-internal cleanup mechanism. key is ignored
235
--- src/json_login.c
+++ src/json_login.c
@@ -105,11 +105,12 @@
105105
jseed = json_getenv("cs") /* name used by HTML interface */;
106106
}
107107
}
108108
if(jseed){
109109
if( cson_value_is_number(jseed) ){
110
- sprintf(seedBuffer, "%"CSON_INT_T_PFMT, cson_value_get_integer(jseed));
110
+ sqlite3_snprintf((int)SeedBufLen, seedBuffer, "%"CSON_INT_T_PFMT,
111
+ cson_value_get_integer(jseed));
111112
anonSeed = seedBuffer;
112113
}else if( cson_value_is_string(jseed) ){
113114
anonSeed = cson_string_cstr(cson_value_get_string(jseed));
114115
}
115116
}
@@ -213,11 +214,11 @@
213214
*/
214215
cson_value * json_page_anon_password(void){
215216
cson_value * v = cson_value_new_object();
216217
cson_object * o = cson_value_get_object(v);
217218
unsigned const int seed = captcha_seed();
218
- char const * zCaptcha = captcha_decode(seed);
219
+ char const * zCaptcha = captcha_decode(seed, 0);
219220
cson_object_set(o, "seed",
220221
cson_value_new_integer( (cson_int_t)seed )
221222
);
222223
cson_object_set(o, "password",
223224
cson_value_new_string( zCaptcha, strlen(zCaptcha) )
224225
--- src/json_login.c
+++ src/json_login.c
@@ -105,11 +105,12 @@
105 jseed = json_getenv("cs") /* name used by HTML interface */;
106 }
107 }
108 if(jseed){
109 if( cson_value_is_number(jseed) ){
110 sprintf(seedBuffer, "%"CSON_INT_T_PFMT, cson_value_get_integer(jseed));
 
111 anonSeed = seedBuffer;
112 }else if( cson_value_is_string(jseed) ){
113 anonSeed = cson_string_cstr(cson_value_get_string(jseed));
114 }
115 }
@@ -213,11 +214,11 @@
213 */
214 cson_value * json_page_anon_password(void){
215 cson_value * v = cson_value_new_object();
216 cson_object * o = cson_value_get_object(v);
217 unsigned const int seed = captcha_seed();
218 char const * zCaptcha = captcha_decode(seed);
219 cson_object_set(o, "seed",
220 cson_value_new_integer( (cson_int_t)seed )
221 );
222 cson_object_set(o, "password",
223 cson_value_new_string( zCaptcha, strlen(zCaptcha) )
224
--- src/json_login.c
+++ src/json_login.c
@@ -105,11 +105,12 @@
105 jseed = json_getenv("cs") /* name used by HTML interface */;
106 }
107 }
108 if(jseed){
109 if( cson_value_is_number(jseed) ){
110 sqlite3_snprintf((int)SeedBufLen, seedBuffer, "%"CSON_INT_T_PFMT,
111 cson_value_get_integer(jseed));
112 anonSeed = seedBuffer;
113 }else if( cson_value_is_string(jseed) ){
114 anonSeed = cson_string_cstr(cson_value_get_string(jseed));
115 }
116 }
@@ -213,11 +214,11 @@
214 */
215 cson_value * json_page_anon_password(void){
216 cson_value * v = cson_value_new_object();
217 cson_object * o = cson_value_get_object(v);
218 unsigned const int seed = captcha_seed();
219 char const * zCaptcha = captcha_decode(seed, 0);
220 cson_object_set(o, "seed",
221 cson_value_new_integer( (cson_int_t)seed )
222 );
223 cson_object_set(o, "password",
224 cson_value_new_string( zCaptcha, strlen(zCaptcha) )
225
+79 -24
--- src/login.c
+++ src/login.c
@@ -154,17 +154,22 @@
154154
const char *zPassword, /* The supplied password */
155155
const char *zCS /* The captcha seed value */
156156
){
157157
const char *zPw; /* The correct password shown in the captcha */
158158
int uid; /* The user ID of anonymous */
159
+ int n = 0; /* Counter of captcha-secrets */
159160
160161
if( zUsername==0 ) return 0;
161162
else if( zPassword==0 ) return 0;
162163
else if( zCS==0 ) return 0;
163164
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
164
- zPw = captcha_decode((unsigned int)atoi(zCS));
165
- if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
165
+ while( 1/*exit-by-break*/ ){
166
+ zPw = captcha_decode((unsigned int)atoi(zCS), n);
167
+ if( zPw==0 ) return 0;
168
+ if( fossil_stricmp(zPw, zPassword)==0 ) break;
169
+ n++;
170
+ }
166171
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
167172
" AND octet_length(pw)>0 AND octet_length(cap)>0");
168173
return uid;
169174
}
170175
@@ -346,29 +351,30 @@
346351
** *zCookieDest and the caller must eventually free() it.
347352
**
348353
** If bSessionCookie is true, the cookie will be a session cookie.
349354
*/
350355
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
351
- const char *zNow; /* Current time (julian day number) */
356
+ char *zNow; /* Current time (julian day number) */
352357
char *zCookie; /* The login cookie */
353358
const char *zCookieName; /* Name of the login cookie */
354359
Blob b; /* Blob used during cookie construction */
355360
int expires = bSessionCookie ? 0 : 6*3600;
356361
zCookieName = login_cookie_name();
357362
zNow = db_text("0", "SELECT julianday('now')");
358363
assert( zCookieName && zNow );
359364
blob_init(&b, zNow, -1);
360
- blob_appendf(&b, "/%s", db_get("captcha-secret",""));
365
+ blob_appendf(&b, "/%z", captcha_secret(0));
361366
sha1sum_blob(&b, &b);
362367
zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
363368
blob_reset(&b);
364369
cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
365370
if( zCookieDest ){
366371
*zCookieDest = zCookie;
367372
}else{
368373
free(zCookie);
369374
}
375
+ fossil_free(zNow);
370376
}
371377
372378
/*
373379
** "Unsets" the login cookie (insofar as cookies can be unset) and
374380
** clears the current user's (g.userUid) login information from the
@@ -806,11 +812,11 @@
806812
@ <td><input type="submit" name="pwreset" value="Reset My Password">
807813
@ </tr>
808814
}
809815
@ </table>
810816
if( zAnonPw && !noAnon ){
811
- const char *zDecoded = captcha_decode(uSeed);
817
+ const char *zDecoded = captcha_decode(uSeed, 0);
812818
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
813819
char *zCaptcha = captcha_render(zDecoded);
814820
815821
@ <p><input type="hidden" name="cs" value="%u(uSeed)">
816822
@ Visitors may enter <b>anonymous</b> as the user-ID with
@@ -838,13 +844,17 @@
838844
if( db_table_exists("repository","forumpost") ){
839845
@ <hr><p>
840846
@ <a href="%R/timeline?ss=v&y=f&vfx&u=%t(g.zLogin)">Forum
841847
@ post timeline</a> for user <b>%h(g.zLogin)</b></p>
842848
}
843
- @ <hr><p>
844
- @ Select your preferred <a href="%R/skins">site skin</a>.
845
- @ </p>
849
+ }
850
+ @ <hr><p>
851
+ @ Select your preferred <a href="%R/skins">site skin</a>.
852
+ @ </p>
853
+ @ <hr><p>
854
+ @ Manage your <a href="%R/cookies">cookies</a>.</p>
855
+ if( login_is_individual() ){
846856
if( g.perm.Password ){
847857
char *zRPW = fossil_random_password(12);
848858
@ <hr>
849859
@ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
850860
form_begin(0, "%R/login");
@@ -1310,11 +1320,40 @@
13101320
*/
13111321
g.isHuman = 0;
13121322
(void)exclude_spiders(0);
13131323
cgi_reply();
13141324
fossil_exit(0);
1315
-}
1325
+}
1326
+
1327
+/*
1328
+** When this routine is called, we know that the request does not
1329
+** have a login on the present repository. This routine checks to
1330
+** see if their login cookie might be for another member of the
1331
+** login-group.
1332
+**
1333
+** If this repository is not a part of any login group, then this
1334
+** routine always returns false.
1335
+**
1336
+** If this repository is part of a login group, and the login cookie
1337
+** appears to be well-formed, then return true. That might be a
1338
+** false-positive, as we don't actually check to see if the login
1339
+** cookie is valid for some other repository. But false-positives
1340
+** are ok. This routine is used for robot defense only.
1341
+*/
1342
+int login_cookie_wellformed(void){
1343
+ const char *zCookie;
1344
+ int n;
1345
+ zCookie = P(login_cookie_name());
1346
+ if( zCookie==0 ){
1347
+ return 0;
1348
+ }
1349
+ if( !db_exists("SELECT 1 FROM config WHERE name='login-group-code'") ){
1350
+ return 0;
1351
+ }
1352
+ for(n=0; fossil_isXdigit(zCookie[n]); n++){}
1353
+ return n>48 && zCookie[n]=='/' && zCookie[n+1]!=0;
1354
+}
13161355
13171356
/*
13181357
** This routine examines the login cookie to see if it exists and
13191358
** is valid. If the login cookie checks out, it then sets global
13201359
** variables appropriately.
@@ -1397,32 +1436,48 @@
13971436
** too old and the sha1 hash of TIME/SECRET must match HASH.
13981437
** SECRET is the "captcha-secret" value in the repository.
13991438
*/
14001439
double rTime = atof(zArg);
14011440
Blob b;
1402
- blob_zero(&b);
1403
- blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
1404
- sha1sum_blob(&b, &b);
1405
- if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1406
- uid = db_int(0,
1407
- "SELECT uid FROM user WHERE login='anonymous'"
1408
- " AND octet_length(cap)>0"
1409
- " AND octet_length(pw)>0"
1410
- " AND %.17g+0.25>julianday('now')",
1411
- rTime
1412
- );
1413
- }
1441
+ char *zSecret;
1442
+ int n = 0;
1443
+
1444
+ do{
1445
+ blob_zero(&b);
1446
+ zSecret = captcha_secret(n++);
1447
+ if( zSecret==0 ) break;
1448
+ blob_appendf(&b, "%s/%s", zArg, zSecret);
1449
+ sha1sum_blob(&b, &b);
1450
+ if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1451
+ uid = db_int(0,
1452
+ "SELECT uid FROM user WHERE login='anonymous'"
1453
+ " AND octet_length(cap)>0"
1454
+ " AND octet_length(pw)>0"
1455
+ " AND %.17g+0.25>julianday('now')",
1456
+ rTime
1457
+ );
1458
+ }
1459
+ }while( uid==0 );
14141460
blob_reset(&b);
14151461
}else{
14161462
/* Cookies of the form "HASH/CODE/USER". Search first in the
14171463
** local user table, then the user table for project CODE if we
14181464
** are part of a login-group.
14191465
*/
14201466
uid = login_find_user(zUser, zHash);
14211467
if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
14221468
uid = login_find_user(zUser, zHash);
1423
- if( uid ) record_login_attempt(zUser, zIpAddr, 1);
1469
+ if( uid ){
1470
+ record_login_attempt(zUser, zIpAddr, 1);
1471
+ }else{
1472
+ /* The login cookie is a valid login for project CODE, but no
1473
+ ** user named USER exists on this repository. Cannot login as
1474
+ ** USER, but at least give them "anonymous" login. */
1475
+ uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
1476
+ " AND octet_length(cap)>0"
1477
+ " AND octet_length(pw)>0");
1478
+ }
14241479
}
14251480
}
14261481
login_create_csrf_secret(zHash);
14271482
}
14281483
@@ -2173,11 +2228,11 @@
21732228
if( captchaIsCorrect ){
21742229
uSeed = strtoul(P("captchaseed"),0,10);
21752230
}else{
21762231
uSeed = captcha_seed();
21772232
}
2178
- zDecoded = captcha_decode(uSeed);
2233
+ zDecoded = captcha_decode(uSeed, 0);
21792234
zCaptcha = captcha_render(zDecoded);
21802235
21812236
style_header("Register");
21822237
/* Print out the registration form. */
21832238
g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
@@ -2383,11 +2438,11 @@
23832438
if( captchaIsCorrect ){
23842439
uSeed = strtoul(P("captchaseed"),0,10);
23852440
}else{
23862441
uSeed = captcha_seed();
23872442
}
2388
- zDecoded = captcha_decode(uSeed);
2443
+ zDecoded = captcha_decode(uSeed, 0);
23892444
zCaptcha = captcha_render(zDecoded);
23902445
23912446
style_header("Request Password Reset");
23922447
/* Print out the registration form. */
23932448
g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
23942449
--- src/login.c
+++ src/login.c
@@ -154,17 +154,22 @@
154 const char *zPassword, /* The supplied password */
155 const char *zCS /* The captcha seed value */
156 ){
157 const char *zPw; /* The correct password shown in the captcha */
158 int uid; /* The user ID of anonymous */
 
159
160 if( zUsername==0 ) return 0;
161 else if( zPassword==0 ) return 0;
162 else if( zCS==0 ) return 0;
163 else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
164 zPw = captcha_decode((unsigned int)atoi(zCS));
165 if( fossil_stricmp(zPw, zPassword)!=0 ) return 0;
 
 
 
 
166 uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
167 " AND octet_length(pw)>0 AND octet_length(cap)>0");
168 return uid;
169 }
170
@@ -346,29 +351,30 @@
346 ** *zCookieDest and the caller must eventually free() it.
347 **
348 ** If bSessionCookie is true, the cookie will be a session cookie.
349 */
350 void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
351 const char *zNow; /* Current time (julian day number) */
352 char *zCookie; /* The login cookie */
353 const char *zCookieName; /* Name of the login cookie */
354 Blob b; /* Blob used during cookie construction */
355 int expires = bSessionCookie ? 0 : 6*3600;
356 zCookieName = login_cookie_name();
357 zNow = db_text("0", "SELECT julianday('now')");
358 assert( zCookieName && zNow );
359 blob_init(&b, zNow, -1);
360 blob_appendf(&b, "/%s", db_get("captcha-secret",""));
361 sha1sum_blob(&b, &b);
362 zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
363 blob_reset(&b);
364 cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
365 if( zCookieDest ){
366 *zCookieDest = zCookie;
367 }else{
368 free(zCookie);
369 }
 
370 }
371
372 /*
373 ** "Unsets" the login cookie (insofar as cookies can be unset) and
374 ** clears the current user's (g.userUid) login information from the
@@ -806,11 +812,11 @@
806 @ <td><input type="submit" name="pwreset" value="Reset My Password">
807 @ </tr>
808 }
809 @ </table>
810 if( zAnonPw && !noAnon ){
811 const char *zDecoded = captcha_decode(uSeed);
812 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
813 char *zCaptcha = captcha_render(zDecoded);
814
815 @ <p><input type="hidden" name="cs" value="%u(uSeed)">
816 @ Visitors may enter <b>anonymous</b> as the user-ID with
@@ -838,13 +844,17 @@
838 if( db_table_exists("repository","forumpost") ){
839 @ <hr><p>
840 @ <a href="%R/timeline?ss=v&y=f&vfx&u=%t(g.zLogin)">Forum
841 @ post timeline</a> for user <b>%h(g.zLogin)</b></p>
842 }
843 @ <hr><p>
844 @ Select your preferred <a href="%R/skins">site skin</a>.
845 @ </p>
 
 
 
 
846 if( g.perm.Password ){
847 char *zRPW = fossil_random_password(12);
848 @ <hr>
849 @ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
850 form_begin(0, "%R/login");
@@ -1310,11 +1320,40 @@
1310 */
1311 g.isHuman = 0;
1312 (void)exclude_spiders(0);
1313 cgi_reply();
1314 fossil_exit(0);
1315 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1316
1317 /*
1318 ** This routine examines the login cookie to see if it exists and
1319 ** is valid. If the login cookie checks out, it then sets global
1320 ** variables appropriately.
@@ -1397,32 +1436,48 @@
1397 ** too old and the sha1 hash of TIME/SECRET must match HASH.
1398 ** SECRET is the "captcha-secret" value in the repository.
1399 */
1400 double rTime = atof(zArg);
1401 Blob b;
1402 blob_zero(&b);
1403 blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
1404 sha1sum_blob(&b, &b);
1405 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1406 uid = db_int(0,
1407 "SELECT uid FROM user WHERE login='anonymous'"
1408 " AND octet_length(cap)>0"
1409 " AND octet_length(pw)>0"
1410 " AND %.17g+0.25>julianday('now')",
1411 rTime
1412 );
1413 }
 
 
 
 
 
 
 
1414 blob_reset(&b);
1415 }else{
1416 /* Cookies of the form "HASH/CODE/USER". Search first in the
1417 ** local user table, then the user table for project CODE if we
1418 ** are part of a login-group.
1419 */
1420 uid = login_find_user(zUser, zHash);
1421 if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
1422 uid = login_find_user(zUser, zHash);
1423 if( uid ) record_login_attempt(zUser, zIpAddr, 1);
 
 
 
 
 
 
 
 
 
1424 }
1425 }
1426 login_create_csrf_secret(zHash);
1427 }
1428
@@ -2173,11 +2228,11 @@
2173 if( captchaIsCorrect ){
2174 uSeed = strtoul(P("captchaseed"),0,10);
2175 }else{
2176 uSeed = captcha_seed();
2177 }
2178 zDecoded = captcha_decode(uSeed);
2179 zCaptcha = captcha_render(zDecoded);
2180
2181 style_header("Register");
2182 /* Print out the registration form. */
2183 g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
@@ -2383,11 +2438,11 @@
2383 if( captchaIsCorrect ){
2384 uSeed = strtoul(P("captchaseed"),0,10);
2385 }else{
2386 uSeed = captcha_seed();
2387 }
2388 zDecoded = captcha_decode(uSeed);
2389 zCaptcha = captcha_render(zDecoded);
2390
2391 style_header("Request Password Reset");
2392 /* Print out the registration form. */
2393 g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
2394
--- src/login.c
+++ src/login.c
@@ -154,17 +154,22 @@
154 const char *zPassword, /* The supplied password */
155 const char *zCS /* The captcha seed value */
156 ){
157 const char *zPw; /* The correct password shown in the captcha */
158 int uid; /* The user ID of anonymous */
159 int n = 0; /* Counter of captcha-secrets */
160
161 if( zUsername==0 ) return 0;
162 else if( zPassword==0 ) return 0;
163 else if( zCS==0 ) return 0;
164 else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
165 while( 1/*exit-by-break*/ ){
166 zPw = captcha_decode((unsigned int)atoi(zCS), n);
167 if( zPw==0 ) return 0;
168 if( fossil_stricmp(zPw, zPassword)==0 ) break;
169 n++;
170 }
171 uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
172 " AND octet_length(pw)>0 AND octet_length(cap)>0");
173 return uid;
174 }
175
@@ -346,29 +351,30 @@
351 ** *zCookieDest and the caller must eventually free() it.
352 **
353 ** If bSessionCookie is true, the cookie will be a session cookie.
354 */
355 void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
356 char *zNow; /* Current time (julian day number) */
357 char *zCookie; /* The login cookie */
358 const char *zCookieName; /* Name of the login cookie */
359 Blob b; /* Blob used during cookie construction */
360 int expires = bSessionCookie ? 0 : 6*3600;
361 zCookieName = login_cookie_name();
362 zNow = db_text("0", "SELECT julianday('now')");
363 assert( zCookieName && zNow );
364 blob_init(&b, zNow, -1);
365 blob_appendf(&b, "/%z", captcha_secret(0));
366 sha1sum_blob(&b, &b);
367 zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
368 blob_reset(&b);
369 cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
370 if( zCookieDest ){
371 *zCookieDest = zCookie;
372 }else{
373 free(zCookie);
374 }
375 fossil_free(zNow);
376 }
377
378 /*
379 ** "Unsets" the login cookie (insofar as cookies can be unset) and
380 ** clears the current user's (g.userUid) login information from the
@@ -806,11 +812,11 @@
812 @ <td><input type="submit" name="pwreset" value="Reset My Password">
813 @ </tr>
814 }
815 @ </table>
816 if( zAnonPw && !noAnon ){
817 const char *zDecoded = captcha_decode(uSeed, 0);
818 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
819 char *zCaptcha = captcha_render(zDecoded);
820
821 @ <p><input type="hidden" name="cs" value="%u(uSeed)">
822 @ Visitors may enter <b>anonymous</b> as the user-ID with
@@ -838,13 +844,17 @@
844 if( db_table_exists("repository","forumpost") ){
845 @ <hr><p>
846 @ <a href="%R/timeline?ss=v&y=f&vfx&u=%t(g.zLogin)">Forum
847 @ post timeline</a> for user <b>%h(g.zLogin)</b></p>
848 }
849 }
850 @ <hr><p>
851 @ Select your preferred <a href="%R/skins">site skin</a>.
852 @ </p>
853 @ <hr><p>
854 @ Manage your <a href="%R/cookies">cookies</a>.</p>
855 if( login_is_individual() ){
856 if( g.perm.Password ){
857 char *zRPW = fossil_random_password(12);
858 @ <hr>
859 @ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
860 form_begin(0, "%R/login");
@@ -1310,11 +1320,40 @@
1320 */
1321 g.isHuman = 0;
1322 (void)exclude_spiders(0);
1323 cgi_reply();
1324 fossil_exit(0);
1325 }
1326
1327 /*
1328 ** When this routine is called, we know that the request does not
1329 ** have a login on the present repository. This routine checks to
1330 ** see if their login cookie might be for another member of the
1331 ** login-group.
1332 **
1333 ** If this repository is not a part of any login group, then this
1334 ** routine always returns false.
1335 **
1336 ** If this repository is part of a login group, and the login cookie
1337 ** appears to be well-formed, then return true. That might be a
1338 ** false-positive, as we don't actually check to see if the login
1339 ** cookie is valid for some other repository. But false-positives
1340 ** are ok. This routine is used for robot defense only.
1341 */
1342 int login_cookie_wellformed(void){
1343 const char *zCookie;
1344 int n;
1345 zCookie = P(login_cookie_name());
1346 if( zCookie==0 ){
1347 return 0;
1348 }
1349 if( !db_exists("SELECT 1 FROM config WHERE name='login-group-code'") ){
1350 return 0;
1351 }
1352 for(n=0; fossil_isXdigit(zCookie[n]); n++){}
1353 return n>48 && zCookie[n]=='/' && zCookie[n+1]!=0;
1354 }
1355
1356 /*
1357 ** This routine examines the login cookie to see if it exists and
1358 ** is valid. If the login cookie checks out, it then sets global
1359 ** variables appropriately.
@@ -1397,32 +1436,48 @@
1436 ** too old and the sha1 hash of TIME/SECRET must match HASH.
1437 ** SECRET is the "captcha-secret" value in the repository.
1438 */
1439 double rTime = atof(zArg);
1440 Blob b;
1441 char *zSecret;
1442 int n = 0;
1443
1444 do{
1445 blob_zero(&b);
1446 zSecret = captcha_secret(n++);
1447 if( zSecret==0 ) break;
1448 blob_appendf(&b, "%s/%s", zArg, zSecret);
1449 sha1sum_blob(&b, &b);
1450 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1451 uid = db_int(0,
1452 "SELECT uid FROM user WHERE login='anonymous'"
1453 " AND octet_length(cap)>0"
1454 " AND octet_length(pw)>0"
1455 " AND %.17g+0.25>julianday('now')",
1456 rTime
1457 );
1458 }
1459 }while( uid==0 );
1460 blob_reset(&b);
1461 }else{
1462 /* Cookies of the form "HASH/CODE/USER". Search first in the
1463 ** local user table, then the user table for project CODE if we
1464 ** are part of a login-group.
1465 */
1466 uid = login_find_user(zUser, zHash);
1467 if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
1468 uid = login_find_user(zUser, zHash);
1469 if( uid ){
1470 record_login_attempt(zUser, zIpAddr, 1);
1471 }else{
1472 /* The login cookie is a valid login for project CODE, but no
1473 ** user named USER exists on this repository. Cannot login as
1474 ** USER, but at least give them "anonymous" login. */
1475 uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
1476 " AND octet_length(cap)>0"
1477 " AND octet_length(pw)>0");
1478 }
1479 }
1480 }
1481 login_create_csrf_secret(zHash);
1482 }
1483
@@ -2173,11 +2228,11 @@
2228 if( captchaIsCorrect ){
2229 uSeed = strtoul(P("captchaseed"),0,10);
2230 }else{
2231 uSeed = captcha_seed();
2232 }
2233 zDecoded = captcha_decode(uSeed, 0);
2234 zCaptcha = captcha_render(zDecoded);
2235
2236 style_header("Register");
2237 /* Print out the registration form. */
2238 g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
@@ -2383,11 +2438,11 @@
2438 if( captchaIsCorrect ){
2439 uSeed = strtoul(P("captchaseed"),0,10);
2440 }else{
2441 uSeed = captcha_seed();
2442 }
2443 zDecoded = captcha_decode(uSeed, 0);
2444 zCaptcha = captcha_render(zDecoded);
2445
2446 style_header("Request Password Reset");
2447 /* Print out the registration form. */
2448 g.perm.Hyperlink = 1; /* Artificially enable hyperlinks */
2449
+5 -2
--- src/main.c
+++ src/main.c
@@ -21,11 +21,10 @@
2121
#include "VERSION.h"
2222
#include "config.h"
2323
#if defined(_WIN32)
2424
# include <windows.h>
2525
# include <io.h>
26
-# define isatty(h) _isatty(h)
2726
# define GETPID (int)GetCurrentProcessId
2827
#endif
2928
3029
/* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
3130
#if USE_SEE
@@ -705,11 +704,11 @@
705704
int rc;
706705
707706
g.zPhase = "init";
708707
#if !defined(_WIN32_WCE)
709708
if( fossil_getenv("FOSSIL_BREAK") ){
710
- if( isatty(0) && isatty(2) ){
709
+ if( fossil_isatty(0) && fossil_isatty(2) ){
711710
fprintf(stderr,
712711
"attach debugger to process %d and press any key to continue.\n",
713712
GETPID());
714713
fgetc(stdin);
715714
}else{
@@ -3573,10 +3572,14 @@
35733572
g.httpSSLConn = 0;
35743573
}
35753574
#endif /* FOSSIL_ENABLE_SSL */
35763575
35773576
#else /* WIN32 */
3577
+ find_server_repository(2, 0);
3578
+ if( fossil_strcmp(g.zRepositoryName,"/")==0 ){
3579
+ allowRepoList = 1;
3580
+ }
35783581
/* Win32 implementation */
35793582
if( allowRepoList ){
35803583
flags |= HTTP_SERVER_REPOLIST;
35813584
}
35823585
if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
35833586
--- src/main.c
+++ src/main.c
@@ -21,11 +21,10 @@
21 #include "VERSION.h"
22 #include "config.h"
23 #if defined(_WIN32)
24 # include <windows.h>
25 # include <io.h>
26 # define isatty(h) _isatty(h)
27 # define GETPID (int)GetCurrentProcessId
28 #endif
29
30 /* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
31 #if USE_SEE
@@ -705,11 +704,11 @@
705 int rc;
706
707 g.zPhase = "init";
708 #if !defined(_WIN32_WCE)
709 if( fossil_getenv("FOSSIL_BREAK") ){
710 if( isatty(0) && isatty(2) ){
711 fprintf(stderr,
712 "attach debugger to process %d and press any key to continue.\n",
713 GETPID());
714 fgetc(stdin);
715 }else{
@@ -3573,10 +3572,14 @@
3573 g.httpSSLConn = 0;
3574 }
3575 #endif /* FOSSIL_ENABLE_SSL */
3576
3577 #else /* WIN32 */
 
 
 
 
3578 /* Win32 implementation */
3579 if( allowRepoList ){
3580 flags |= HTTP_SERVER_REPOLIST;
3581 }
3582 if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
3583
--- src/main.c
+++ src/main.c
@@ -21,11 +21,10 @@
21 #include "VERSION.h"
22 #include "config.h"
23 #if defined(_WIN32)
24 # include <windows.h>
25 # include <io.h>
 
26 # define GETPID (int)GetCurrentProcessId
27 #endif
28
29 /* BUGBUG: This (PID_T) does not work inside of INTERFACE block. */
30 #if USE_SEE
@@ -705,11 +704,11 @@
704 int rc;
705
706 g.zPhase = "init";
707 #if !defined(_WIN32_WCE)
708 if( fossil_getenv("FOSSIL_BREAK") ){
709 if( fossil_isatty(0) && fossil_isatty(2) ){
710 fprintf(stderr,
711 "attach debugger to process %d and press any key to continue.\n",
712 GETPID());
713 fgetc(stdin);
714 }else{
@@ -3573,10 +3572,14 @@
3572 g.httpSSLConn = 0;
3573 }
3574 #endif /* FOSSIL_ENABLE_SSL */
3575
3576 #else /* WIN32 */
3577 find_server_repository(2, 0);
3578 if( fossil_strcmp(g.zRepositoryName,"/")==0 ){
3579 allowRepoList = 1;
3580 }
3581 /* Win32 implementation */
3582 if( allowRepoList ){
3583 flags |= HTTP_SERVER_REPOLIST;
3584 }
3585 if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
3586
+2 -2
--- src/markdown.md
+++ src/markdown.md
@@ -130,12 +130,12 @@
130130
| Row 4 Col 1 | Row 4 Col 2 | Row 4 Col 3 |
131131
132132
> The first row is a header if followed by a horizontal rule or a blank line.
133133
134134
> Placing **:** at the left, both, or right sides of a cell gives left-aligned,
135
-> centered, or right-aligned text, respectively. By default, header cells are
136
-> centered, and body cells are left-aligned.
135
+> centered, or right-aligned text, respectively. By default, both header and
136
+> body cells are left-aligned.
137137
138138
> The leftmost or rightmost **\|** is required only if the first or last column,
139139
> respectively, contains at least one blank cell.
140140
141141
## Diagrams ##
142142
--- src/markdown.md
+++ src/markdown.md
@@ -130,12 +130,12 @@
130 | Row 4 Col 1 | Row 4 Col 2 | Row 4 Col 3 |
131
132 > The first row is a header if followed by a horizontal rule or a blank line.
133
134 > Placing **:** at the left, both, or right sides of a cell gives left-aligned,
135 > centered, or right-aligned text, respectively. By default, header cells are
136 > centered, and body cells are left-aligned.
137
138 > The leftmost or rightmost **\|** is required only if the first or last column,
139 > respectively, contains at least one blank cell.
140
141 ## Diagrams ##
142
--- src/markdown.md
+++ src/markdown.md
@@ -130,12 +130,12 @@
130 | Row 4 Col 1 | Row 4 Col 2 | Row 4 Col 3 |
131
132 > The first row is a header if followed by a horizontal rule or a blank line.
133
134 > Placing **:** at the left, both, or right sides of a cell gives left-aligned,
135 > centered, or right-aligned text, respectively. By default, both header and
136 > body cells are left-aligned.
137
138 > The leftmost or rightmost **\|** is required only if the first or last column,
139 > respectively, contains at least one blank cell.
140
141 ## Diagrams ##
142
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -306,19 +306,19 @@
306306
}else{
307307
blob_append_literal(ob, " <td");
308308
}
309309
switch( flags & MKD_CELL_ALIGN_MASK ){
310310
case MKD_CELL_ALIGN_LEFT: {
311
- blob_append_literal(ob, " align=\"left\"");
311
+ blob_append_literal(ob, " style=\"text-align:left\"");
312312
break;
313313
}
314314
case MKD_CELL_ALIGN_RIGHT: {
315
- blob_append_literal(ob, " align=\"right\"");
315
+ blob_append_literal(ob, " style=\"text-align:right\"");
316316
break;
317317
}
318318
case MKD_CELL_ALIGN_CENTER: {
319
- blob_append_literal(ob, " align=\"center\"");
319
+ blob_append_literal(ob, " style=\"text-align:center\"");
320320
break;
321321
}
322322
}
323323
blob_append_literal(ob, ">");
324324
blob_appendb(ob, text);
325325
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -306,19 +306,19 @@
306 }else{
307 blob_append_literal(ob, " <td");
308 }
309 switch( flags & MKD_CELL_ALIGN_MASK ){
310 case MKD_CELL_ALIGN_LEFT: {
311 blob_append_literal(ob, " align=\"left\"");
312 break;
313 }
314 case MKD_CELL_ALIGN_RIGHT: {
315 blob_append_literal(ob, " align=\"right\"");
316 break;
317 }
318 case MKD_CELL_ALIGN_CENTER: {
319 blob_append_literal(ob, " align=\"center\"");
320 break;
321 }
322 }
323 blob_append_literal(ob, ">");
324 blob_appendb(ob, text);
325
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -306,19 +306,19 @@
306 }else{
307 blob_append_literal(ob, " <td");
308 }
309 switch( flags & MKD_CELL_ALIGN_MASK ){
310 case MKD_CELL_ALIGN_LEFT: {
311 blob_append_literal(ob, " style=\"text-align:left\"");
312 break;
313 }
314 case MKD_CELL_ALIGN_RIGHT: {
315 blob_append_literal(ob, " style=\"text-align:right\"");
316 break;
317 }
318 case MKD_CELL_ALIGN_CENTER: {
319 blob_append_literal(ob, " style=\"text-align:center\"");
320 break;
321 }
322 }
323 blob_append_literal(ob, ">");
324 blob_appendb(ob, text);
325
+2 -1
--- src/patch.c
+++ src/patch.c
@@ -384,11 +384,12 @@
384384
Blob cmd;
385385
386386
blob_init(&cmd, 0, 0);
387387
if( unsaved_changes(0) ){
388388
if( (mFlags & PATCH_FORCE)==0 ){
389
- fossil_fatal("there are unsaved changes in the current check-out");
389
+ fossil_fatal("Cannot apply patch: there are unsaved changes "
390
+ "in the current check-out");
390391
}else{
391392
blob_appendf(&cmd, "%$ revert", g.nameOfExe);
392393
if( mFlags & PATCH_DRYRUN ){
393394
fossil_print("%s\n", blob_str(&cmd));
394395
}else{
395396
--- src/patch.c
+++ src/patch.c
@@ -384,11 +384,12 @@
384 Blob cmd;
385
386 blob_init(&cmd, 0, 0);
387 if( unsaved_changes(0) ){
388 if( (mFlags & PATCH_FORCE)==0 ){
389 fossil_fatal("there are unsaved changes in the current check-out");
 
390 }else{
391 blob_appendf(&cmd, "%$ revert", g.nameOfExe);
392 if( mFlags & PATCH_DRYRUN ){
393 fossil_print("%s\n", blob_str(&cmd));
394 }else{
395
--- src/patch.c
+++ src/patch.c
@@ -384,11 +384,12 @@
384 Blob cmd;
385
386 blob_init(&cmd, 0, 0);
387 if( unsaved_changes(0) ){
388 if( (mFlags & PATCH_FORCE)==0 ){
389 fossil_fatal("Cannot apply patch: there are unsaved changes "
390 "in the current check-out");
391 }else{
392 blob_appendf(&cmd, "%$ revert", g.nameOfExe);
393 if( mFlags & PATCH_DRYRUN ){
394 fossil_print("%s\n", blob_str(&cmd));
395 }else{
396
+1 -1
--- src/printf.c
+++ src/printf.c
@@ -1269,8 +1269,8 @@
12691269
void fossil_binary_mode(FILE *p){
12701270
#if defined(_WIN32)
12711271
_setmode(_fileno(p), _O_BINARY);
12721272
#endif
12731273
#ifdef __EMX__ /* OS/2 */
1274
- setmode(fileno(p), O_BINARY);
1274
+ setmode(fossil_fileno(p), O_BINARY);
12751275
#endif
12761276
}
12771277
--- src/printf.c
+++ src/printf.c
@@ -1269,8 +1269,8 @@
1269 void fossil_binary_mode(FILE *p){
1270 #if defined(_WIN32)
1271 _setmode(_fileno(p), _O_BINARY);
1272 #endif
1273 #ifdef __EMX__ /* OS/2 */
1274 setmode(fileno(p), O_BINARY);
1275 #endif
1276 }
1277
--- src/printf.c
+++ src/printf.c
@@ -1269,8 +1269,8 @@
1269 void fossil_binary_mode(FILE *p){
1270 #if defined(_WIN32)
1271 _setmode(_fileno(p), _O_BINARY);
1272 #endif
1273 #ifdef __EMX__ /* OS/2 */
1274 setmode(fossil_fileno(p), O_BINARY);
1275 #endif
1276 }
1277
+69 -24
--- src/setup.c
+++ src/setup.c
@@ -760,10 +760,11 @@
760760
** group.
761761
*/
762762
void setup_login_group(void){
763763
const char *zGroup;
764764
char *zErrMsg = 0;
765
+ Stmt q;
765766
Blob fullName;
766767
char *zSelfRepo;
767768
const char *zRepo = PD("repo", "");
768769
const char *zLogin = PD("login", "");
769770
const char *zPw = PD("pw", "");
@@ -779,10 +780,12 @@
779780
blob_reset(&fullName);
780781
if( P("join")!=0 ){
781782
login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
782783
}else if( P("leave") ){
783784
login_group_leave(&zErrMsg);
785
+ }else if( P("rotate") ){
786
+ captcha_secret_rotate();
784787
}
785788
style_set_current_feature("setup");
786789
style_header("Login Group Configuration");
787790
if( zErrMsg ){
788791
@ <p class="generalError">%s(zErrMsg)</p>
@@ -821,11 +824,10 @@
821824
@
822825
@ <tr><td colspan="3" align="center">
823826
@ <input type="submit" value="Join" name="join"></td></tr>
824827
@ </table></blockquote></div></form>
825828
}else{
826
- Stmt q;
827829
int n = 0;
828830
@ <p>This repository (in the file "%h(zSelfRepo)")
829831
@ is currently part of the "<b>%h(zGroup)</b>" login group.
830832
@ Other repositories in that group are:</p>
831833
@ <table border="0" cellspacing="4">
@@ -849,35 +851,78 @@
849851
db_finalize(&q);
850852
@ </table>
851853
@
852854
@ <p><form action="%R/setup_login_group" method="post"><div>
853855
login_insert_csrf_secret();
854
- @ To leave this login group press
856
+ @ <p>To leave this login group press:
855857
@ <input type="submit" value="Leave Login Group" name="leave">
858
+ @ <p>Setting a common captcha-secret on all repositories in the login-group
859
+ @ allows anonymous logins for one repository in the login group to be used
860
+ @ by all other repositories of the group within the same domain. Warning:
861
+ @ If a captcha dialog was painted before setting the common captcha-secret
862
+ @ and the "Speak password for 'anonymous'" button is pressed afterwards,
863
+ @ the spoken text will be incorrect.
864
+ @ <input type="submit" name="rotate" value="Set common captcha-secret">
856865
@ </form></p>
857
- @ <hr><h2>Implementation Details</h2>
858
- @ <p>The following are fields from the CONFIG table related to login-groups,
859
- @ provided here for instructional and debugging purposes:</p>
860
- @ <table border='1' class='sortable' data-column-types='ttt' \
861
- @ data-init-sort='1'>
862
- @ <thead><tr>
863
- @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
864
- @ </thead><tbody>
865
- db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config"
866
- " WHERE name GLOB 'peer-*'"
867
- " OR name GLOB 'project-*'"
868
- " OR name GLOB 'login-group-*'"
869
- " ORDER BY name");
870
- while( db_step(&q)==SQLITE_ROW ){
871
- @ <tr><td>%h(db_column_text(&q,0))</td>
872
- @ <td>%h(db_column_text(&q,1))</td>
873
- @ <td>%h(db_column_text(&q,2))</td></tr>
874
- }
875
- db_finalize(&q);
876
- @ </tbody></table>
877
- style_table_sorter();
878
- }
866
+ }
867
+ @ <hr><h2>Implementation Details</h2>
868
+ @ <p>The following are fields from the CONFIG table related to login-groups.
869
+ @ </p>
870
+ @ <table border='1' cellspacing="0" cellpadding="4"\
871
+ @ class='sortable' data-column-types='ttt' data-init-sort='1'>
872
+ @ <thead><tr>
873
+ @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
874
+ @ </thead><tbody>
875
+ db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config"
876
+ " WHERE name GLOB 'peer-*'"
877
+ " OR name GLOB 'project-*'"
878
+ " OR name GLOB 'login-group-*'"
879
+ " ORDER BY name");
880
+ while( db_step(&q)==SQLITE_ROW ){
881
+ @ <tr><td>%h(db_column_text(&q,0))</td>
882
+ @ <td>%h(db_column_text(&q,1))</td>
883
+ @ <td>%h(db_column_text(&q,2))</td></tr>
884
+ }
885
+ db_finalize(&q);
886
+ @ </tbody></table>
887
+ @ <h2>Interpretation</h2>
888
+ @ <ul>
889
+ @ <li><p><b>login-group-code</b> &rarr;
890
+ @ A random code assigned to each login-group. The login-group-code is
891
+ @ a unique identifier for the login-group.
892
+ @
893
+ @ <li><p><b>login-group-name</b> &rarr;
894
+ @ The human-readable name of the login-group.
895
+ @
896
+ @ <li><p><b>project-code</b> &rarr;
897
+ @ A random code assigned to each project. The project-code is
898
+ @ a unique identifier for the project. Multiple repositories can share
899
+ @ the same project-code. When two or more repositories have the same
900
+ @ project code, that mean those repositories are clones of each other.
901
+ @ Repositories are only able to sync if they share the same project-code.
902
+ @
903
+ @ <li><p><b>project-description</b> &rarr;
904
+ @ A description of project in this repository. This is a verbose form
905
+ @ of project-name. This description can be edited in the second entry
906
+ @ box on the <a href="./setup_config">Setup/Configuration page</a>.
907
+ @
908
+ @ <li><p><b>project-name</b> &rarr;
909
+ @ The human-readable name for the project. The project-name can be
910
+ @ modified in the first entry on the
911
+ @ <a href="./setup_config">Setup/Configuration page</a>.
912
+ @
913
+ @ <li><p><b>peer-repo-<i>CODE</i></b> &rarr;
914
+ @ <i>CODE</i> is 16-character prefix of the project-code for another
915
+ @ repository that is part of the same login-group. The value is the
916
+ @ filename for the peer repository.
917
+ @
918
+ @ <li><p><b>peer-name-<i>CODE</i></b> &rarr;
919
+ @ <i>CODE</i> is 16-character prefix of the project-code for another
920
+ @ repository that is part of the same login-group. The value is
921
+ @ project-name value for the other repository.
922
+ @ </ul>
923
+ style_table_sorter();
879924
style_finish_page();
880925
}
881926
882927
/*
883928
** WEBPAGE: setup_timeline
884929
--- src/setup.c
+++ src/setup.c
@@ -760,10 +760,11 @@
760 ** group.
761 */
762 void setup_login_group(void){
763 const char *zGroup;
764 char *zErrMsg = 0;
 
765 Blob fullName;
766 char *zSelfRepo;
767 const char *zRepo = PD("repo", "");
768 const char *zLogin = PD("login", "");
769 const char *zPw = PD("pw", "");
@@ -779,10 +780,12 @@
779 blob_reset(&fullName);
780 if( P("join")!=0 ){
781 login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
782 }else if( P("leave") ){
783 login_group_leave(&zErrMsg);
 
 
784 }
785 style_set_current_feature("setup");
786 style_header("Login Group Configuration");
787 if( zErrMsg ){
788 @ <p class="generalError">%s(zErrMsg)</p>
@@ -821,11 +824,10 @@
821 @
822 @ <tr><td colspan="3" align="center">
823 @ <input type="submit" value="Join" name="join"></td></tr>
824 @ </table></blockquote></div></form>
825 }else{
826 Stmt q;
827 int n = 0;
828 @ <p>This repository (in the file "%h(zSelfRepo)")
829 @ is currently part of the "<b>%h(zGroup)</b>" login group.
830 @ Other repositories in that group are:</p>
831 @ <table border="0" cellspacing="4">
@@ -849,35 +851,78 @@
849 db_finalize(&q);
850 @ </table>
851 @
852 @ <p><form action="%R/setup_login_group" method="post"><div>
853 login_insert_csrf_secret();
854 @ To leave this login group press
855 @ <input type="submit" value="Leave Login Group" name="leave">
 
 
 
 
 
 
 
856 @ </form></p>
857 @ <hr><h2>Implementation Details</h2>
858 @ <p>The following are fields from the CONFIG table related to login-groups,
859 @ provided here for instructional and debugging purposes:</p>
860 @ <table border='1' class='sortable' data-column-types='ttt' \
861 @ data-init-sort='1'>
862 @ <thead><tr>
863 @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
864 @ </thead><tbody>
865 db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config"
866 " WHERE name GLOB 'peer-*'"
867 " OR name GLOB 'project-*'"
868 " OR name GLOB 'login-group-*'"
869 " ORDER BY name");
870 while( db_step(&q)==SQLITE_ROW ){
871 @ <tr><td>%h(db_column_text(&q,0))</td>
872 @ <td>%h(db_column_text(&q,1))</td>
873 @ <td>%h(db_column_text(&q,2))</td></tr>
874 }
875 db_finalize(&q);
876 @ </tbody></table>
877 style_table_sorter();
878 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879 style_finish_page();
880 }
881
882 /*
883 ** WEBPAGE: setup_timeline
884
--- src/setup.c
+++ src/setup.c
@@ -760,10 +760,11 @@
760 ** group.
761 */
762 void setup_login_group(void){
763 const char *zGroup;
764 char *zErrMsg = 0;
765 Stmt q;
766 Blob fullName;
767 char *zSelfRepo;
768 const char *zRepo = PD("repo", "");
769 const char *zLogin = PD("login", "");
770 const char *zPw = PD("pw", "");
@@ -779,10 +780,12 @@
780 blob_reset(&fullName);
781 if( P("join")!=0 ){
782 login_group_join(zRepo, 1, zLogin, zPw, zNewName, &zErrMsg);
783 }else if( P("leave") ){
784 login_group_leave(&zErrMsg);
785 }else if( P("rotate") ){
786 captcha_secret_rotate();
787 }
788 style_set_current_feature("setup");
789 style_header("Login Group Configuration");
790 if( zErrMsg ){
791 @ <p class="generalError">%s(zErrMsg)</p>
@@ -821,11 +824,10 @@
824 @
825 @ <tr><td colspan="3" align="center">
826 @ <input type="submit" value="Join" name="join"></td></tr>
827 @ </table></blockquote></div></form>
828 }else{
 
829 int n = 0;
830 @ <p>This repository (in the file "%h(zSelfRepo)")
831 @ is currently part of the "<b>%h(zGroup)</b>" login group.
832 @ Other repositories in that group are:</p>
833 @ <table border="0" cellspacing="4">
@@ -849,35 +851,78 @@
851 db_finalize(&q);
852 @ </table>
853 @
854 @ <p><form action="%R/setup_login_group" method="post"><div>
855 login_insert_csrf_secret();
856 @ <p>To leave this login group press:
857 @ <input type="submit" value="Leave Login Group" name="leave">
858 @ <p>Setting a common captcha-secret on all repositories in the login-group
859 @ allows anonymous logins for one repository in the login group to be used
860 @ by all other repositories of the group within the same domain. Warning:
861 @ If a captcha dialog was painted before setting the common captcha-secret
862 @ and the "Speak password for 'anonymous'" button is pressed afterwards,
863 @ the spoken text will be incorrect.
864 @ <input type="submit" name="rotate" value="Set common captcha-secret">
865 @ </form></p>
866 }
867 @ <hr><h2>Implementation Details</h2>
868 @ <p>The following are fields from the CONFIG table related to login-groups.
869 @ </p>
870 @ <table border='1' cellspacing="0" cellpadding="4"\
871 @ class='sortable' data-column-types='ttt' data-init-sort='1'>
872 @ <thead><tr>
873 @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
874 @ </thead><tbody>
875 db_prepare(&q, "SELECT name, value, datetime(mtime,'unixepoch') FROM config"
876 " WHERE name GLOB 'peer-*'"
877 " OR name GLOB 'project-*'"
878 " OR name GLOB 'login-group-*'"
879 " ORDER BY name");
880 while( db_step(&q)==SQLITE_ROW ){
881 @ <tr><td>%h(db_column_text(&q,0))</td>
882 @ <td>%h(db_column_text(&q,1))</td>
883 @ <td>%h(db_column_text(&q,2))</td></tr>
884 }
885 db_finalize(&q);
886 @ </tbody></table>
887 @ <h2>Interpretation</h2>
888 @ <ul>
889 @ <li><p><b>login-group-code</b> &rarr;
890 @ A random code assigned to each login-group. The login-group-code is
891 @ a unique identifier for the login-group.
892 @
893 @ <li><p><b>login-group-name</b> &rarr;
894 @ The human-readable name of the login-group.
895 @
896 @ <li><p><b>project-code</b> &rarr;
897 @ A random code assigned to each project. The project-code is
898 @ a unique identifier for the project. Multiple repositories can share
899 @ the same project-code. When two or more repositories have the same
900 @ project code, that mean those repositories are clones of each other.
901 @ Repositories are only able to sync if they share the same project-code.
902 @
903 @ <li><p><b>project-description</b> &rarr;
904 @ A description of project in this repository. This is a verbose form
905 @ of project-name. This description can be edited in the second entry
906 @ box on the <a href="./setup_config">Setup/Configuration page</a>.
907 @
908 @ <li><p><b>project-name</b> &rarr;
909 @ The human-readable name for the project. The project-name can be
910 @ modified in the first entry on the
911 @ <a href="./setup_config">Setup/Configuration page</a>.
912 @
913 @ <li><p><b>peer-repo-<i>CODE</i></b> &rarr;
914 @ <i>CODE</i> is 16-character prefix of the project-code for another
915 @ repository that is part of the same login-group. The value is the
916 @ filename for the peer repository.
917 @
918 @ <li><p><b>peer-name-<i>CODE</i></b> &rarr;
919 @ <i>CODE</i> is 16-character prefix of the project-code for another
920 @ repository that is part of the same login-group. The value is
921 @ project-name value for the other repository.
922 @ </ul>
923 style_table_sorter();
924 style_finish_page();
925 }
926
927 /*
928 ** WEBPAGE: setup_timeline
929
--- src/setupuser.c
+++ src/setupuser.c
@@ -939,5 +939,98 @@
939939
@ but less than a <span class="usertype">developer</span>.
940940
@ </p></li>
941941
@ </ul>
942942
style_finish_page();
943943
}
944
+
945
+/*
946
+** WEBPAGE: setup_uinfo
947
+**
948
+** Detailed information about a user account, available to administrators
949
+** only.
950
+**
951
+** u=UID
952
+** l=LOGIN
953
+*/
954
+void setup_uinfo_page(void){
955
+ Stmt q;
956
+ Blob sql;
957
+ const char *zLogin;
958
+ int uid;
959
+
960
+ /* Must have ADMIN privileges to access this page
961
+ */
962
+ login_check_credentials();
963
+ if( !g.perm.Admin ){ login_needed(0); return; }
964
+ style_set_current_feature("setup");
965
+ zLogin = P("l");
966
+ uid = atoi(PD("u","0"));
967
+ if( zLogin==0 && uid==0 ){
968
+ uid = db_int(1,"SELECT uid FROM user");
969
+ }
970
+ blob_init(&sql, 0, 0);
971
+ blob_append_sql(&sql,
972
+ "SELECT "
973
+ /* 0 */ "uid,"
974
+ /* 1 */ "login,"
975
+ /* 2 */ "cap,"
976
+ /* 3 */ "cookie,"
977
+ /* 4 */ "datetime(cexpire),"
978
+ /* 5 */ "info,"
979
+ /* 6 */ "datetime(user.mtime,'unixepoch'),"
980
+ );
981
+ if( db_table_exists("repository","subscriber") ){
982
+ blob_append_sql(&sql,
983
+ /* 7 */ "subscriberId,"
984
+ /* 8 */ "semail,"
985
+ /* 9 */ "sverified,"
986
+ /* 10 */ "date(lastContact+2440587.5)"
987
+ " FROM user LEFT JOIN subscriber ON suname=login"
988
+ );
989
+ }else{
990
+ blob_append_sql(&sql,
991
+ /* 7 */ "NULL,"
992
+ /* 8 */ "NULL,"
993
+ /* 9 */ "NULL,"
994
+ /* 10 */ "NULL"
995
+ " FROM user"
996
+ );
997
+ }
998
+ if( zLogin!=0 ){
999
+ blob_append_sql(&sql, " WHERE login=%Q", zLogin);
1000
+ }else{
1001
+ blob_append_sql(&sql, " WHERE uid=%d", uid);
1002
+ }
1003
+ db_prepare(&q, "%s", blob_sql_text(&sql));
1004
+ blob_zero(&sql);
1005
+ if( db_step(&q)!=SQLITE_ROW ){
1006
+ style_header("No Such User");
1007
+ if( zLogin ){
1008
+ @ <p>Cannot find any information on user %h(zLogin).
1009
+ }else{
1010
+ @ <p>Cannot find any information on userid %d(uid).
1011
+ }
1012
+ style_finish_page();
1013
+ db_finalize(&q);
1014
+ return;
1015
+ }
1016
+ style_header("User %h", db_column_text(&q,1));
1017
+ @ <table class="label-value">
1018
+ @ <tr><th>uid:</th><td>%d(db_column_int(&q,0))
1019
+ @ (<a href="%R/setup_uedit?id=%d(db_column_int(&q,0))">edit</a>)</td></tr>
1020
+ @ <tr><th>login:</th><td>%h(db_column_text(&q,1))</td></tr>
1021
+ @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</th></tr>
1022
+ @ <tr><th valign="top">info:</th>
1023
+ @ <td valign="top"><span style='white-space:pre-line;'>\
1024
+ @ %h(db_column_text(&q,5))</span></td></tr>
1025
+ @ <tr><th>user.mtime:</th><td>%h(db_column_text(&q,6))</td></tr>
1026
+ if( db_column_type(&q,7)!=SQLITE_NULL ){
1027
+ @ <tr><th>subscriberId:</th><td>%d(db_column_int(&q,7))
1028
+ @ (<a href="%R/alerts?sid=%d(db_column_int(&q,7))">edit</a>)</td></tr>
1029
+ @ <tr><th>semail:</th><td>%h(db_column_text(&q,8))</td></tr>
1030
+ @ <tr><th>verified:</th><td>%s(db_column_int(&q,9)?"yes":"no")</td></th>
1031
+ @ <tr><th>lastContact:</th><td>%h(db_column_text(&q,10))</td></tr>
1032
+ }
1033
+ @ </table>
1034
+ db_finalize(&q);
1035
+ style_finish_page();
1036
+}
9441037
--- src/setupuser.c
+++ src/setupuser.c
@@ -939,5 +939,98 @@
939 @ but less than a <span class="usertype">developer</span>.
940 @ </p></li>
941 @ </ul>
942 style_finish_page();
943 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
--- src/setupuser.c
+++ src/setupuser.c
@@ -939,5 +939,98 @@
939 @ but less than a <span class="usertype">developer</span>.
940 @ </p></li>
941 @ </ul>
942 style_finish_page();
943 }
944
945 /*
946 ** WEBPAGE: setup_uinfo
947 **
948 ** Detailed information about a user account, available to administrators
949 ** only.
950 **
951 ** u=UID
952 ** l=LOGIN
953 */
954 void setup_uinfo_page(void){
955 Stmt q;
956 Blob sql;
957 const char *zLogin;
958 int uid;
959
960 /* Must have ADMIN privileges to access this page
961 */
962 login_check_credentials();
963 if( !g.perm.Admin ){ login_needed(0); return; }
964 style_set_current_feature("setup");
965 zLogin = P("l");
966 uid = atoi(PD("u","0"));
967 if( zLogin==0 && uid==0 ){
968 uid = db_int(1,"SELECT uid FROM user");
969 }
970 blob_init(&sql, 0, 0);
971 blob_append_sql(&sql,
972 "SELECT "
973 /* 0 */ "uid,"
974 /* 1 */ "login,"
975 /* 2 */ "cap,"
976 /* 3 */ "cookie,"
977 /* 4 */ "datetime(cexpire),"
978 /* 5 */ "info,"
979 /* 6 */ "datetime(user.mtime,'unixepoch'),"
980 );
981 if( db_table_exists("repository","subscriber") ){
982 blob_append_sql(&sql,
983 /* 7 */ "subscriberId,"
984 /* 8 */ "semail,"
985 /* 9 */ "sverified,"
986 /* 10 */ "date(lastContact+2440587.5)"
987 " FROM user LEFT JOIN subscriber ON suname=login"
988 );
989 }else{
990 blob_append_sql(&sql,
991 /* 7 */ "NULL,"
992 /* 8 */ "NULL,"
993 /* 9 */ "NULL,"
994 /* 10 */ "NULL"
995 " FROM user"
996 );
997 }
998 if( zLogin!=0 ){
999 blob_append_sql(&sql, " WHERE login=%Q", zLogin);
1000 }else{
1001 blob_append_sql(&sql, " WHERE uid=%d", uid);
1002 }
1003 db_prepare(&q, "%s", blob_sql_text(&sql));
1004 blob_zero(&sql);
1005 if( db_step(&q)!=SQLITE_ROW ){
1006 style_header("No Such User");
1007 if( zLogin ){
1008 @ <p>Cannot find any information on user %h(zLogin).
1009 }else{
1010 @ <p>Cannot find any information on userid %d(uid).
1011 }
1012 style_finish_page();
1013 db_finalize(&q);
1014 return;
1015 }
1016 style_header("User %h", db_column_text(&q,1));
1017 @ <table class="label-value">
1018 @ <tr><th>uid:</th><td>%d(db_column_int(&q,0))
1019 @ (<a href="%R/setup_uedit?id=%d(db_column_int(&q,0))">edit</a>)</td></tr>
1020 @ <tr><th>login:</th><td>%h(db_column_text(&q,1))</td></tr>
1021 @ <tr><th>capabilities:</th><td>%h(db_column_text(&q,2))</th></tr>
1022 @ <tr><th valign="top">info:</th>
1023 @ <td valign="top"><span style='white-space:pre-line;'>\
1024 @ %h(db_column_text(&q,5))</span></td></tr>
1025 @ <tr><th>user.mtime:</th><td>%h(db_column_text(&q,6))</td></tr>
1026 if( db_column_type(&q,7)!=SQLITE_NULL ){
1027 @ <tr><th>subscriberId:</th><td>%d(db_column_int(&q,7))
1028 @ (<a href="%R/alerts?sid=%d(db_column_int(&q,7))">edit</a>)</td></tr>
1029 @ <tr><th>semail:</th><td>%h(db_column_text(&q,8))</td></tr>
1030 @ <tr><th>verified:</th><td>%s(db_column_int(&q,9)?"yes":"no")</td></th>
1031 @ <tr><th>lastContact:</th><td>%h(db_column_text(&q,10))</td></tr>
1032 }
1033 @ </table>
1034 db_finalize(&q);
1035 style_finish_page();
1036 }
1037
+4 -4
--- src/shun.c
+++ src/shun.c
@@ -121,14 +121,14 @@
121121
}else{
122122
@ <p class="noMoreShun">Artifact(s)<br>
123123
for( p = zUuid ; *p ; p += strlen(p)+1 ){
124124
@ %s(p)<br>
125125
}
126
- @ will no longer be shunned. But they may not exist in the repository.
127
- @ It may be necessary to rebuild the repository using the
128
- @ <b>fossil rebuild</b> command-line before the artifact content
129
- @ can pulled in from other repositories.</p>
126
+ @ will no longer be shunned but they may not exist in the repository.
127
+ @ It may be necessary to rebuild the repository
128
+ @ before the artifact content can be pulled in
129
+ @ from other repositories.</p>
130130
}
131131
}
132132
if( zUuid && P("add") && cgi_csrf_safe(2) ){
133133
const char *p = zUuid;
134134
int rid, tagid;
135135
--- src/shun.c
+++ src/shun.c
@@ -121,14 +121,14 @@
121 }else{
122 @ <p class="noMoreShun">Artifact(s)<br>
123 for( p = zUuid ; *p ; p += strlen(p)+1 ){
124 @ %s(p)<br>
125 }
126 @ will no longer be shunned. But they may not exist in the repository.
127 @ It may be necessary to rebuild the repository using the
128 @ <b>fossil rebuild</b> command-line before the artifact content
129 @ can pulled in from other repositories.</p>
130 }
131 }
132 if( zUuid && P("add") && cgi_csrf_safe(2) ){
133 const char *p = zUuid;
134 int rid, tagid;
135
--- src/shun.c
+++ src/shun.c
@@ -121,14 +121,14 @@
121 }else{
122 @ <p class="noMoreShun">Artifact(s)<br>
123 for( p = zUuid ; *p ; p += strlen(p)+1 ){
124 @ %s(p)<br>
125 }
126 @ will no longer be shunned but they may not exist in the repository.
127 @ It may be necessary to rebuild the repository
128 @ before the artifact content can be pulled in
129 @ from other repositories.</p>
130 }
131 }
132 if( zUuid && P("add") && cgi_csrf_safe(2) ){
133 const char *p = zUuid;
134 int rid, tagid;
135
+1 -1
--- src/skins.c
+++ src/skins.c
@@ -1345,11 +1345,11 @@
13451345
}
13461346
13471347
/*
13481348
** WEBPAGE: skins
13491349
**
1350
-** Show a list of all of the built-in skins, plus the responsitory skin,
1350
+** Show a list of all of the built-in skins, plus the respository skin,
13511351
** and provide the user with an opportunity to change to any of them.
13521352
*/
13531353
void skins_page(void){
13541354
int i;
13551355
char *zBase = fossil_strdup(g.zTop);
13561356
--- src/skins.c
+++ src/skins.c
@@ -1345,11 +1345,11 @@
1345 }
1346
1347 /*
1348 ** WEBPAGE: skins
1349 **
1350 ** Show a list of all of the built-in skins, plus the responsitory skin,
1351 ** and provide the user with an opportunity to change to any of them.
1352 */
1353 void skins_page(void){
1354 int i;
1355 char *zBase = fossil_strdup(g.zTop);
1356
--- src/skins.c
+++ src/skins.c
@@ -1345,11 +1345,11 @@
1345 }
1346
1347 /*
1348 ** WEBPAGE: skins
1349 **
1350 ** Show a list of all of the built-in skins, plus the respository skin,
1351 ** and provide the user with an opportunity to change to any of them.
1352 */
1353 void skins_page(void){
1354 int i;
1355 char *zBase = fossil_strdup(g.zTop);
1356
+2 -2
--- src/style.c
+++ src/style.c
@@ -989,11 +989,11 @@
989989
}else{
990990
@ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
991991
}
992992
}
993993
}
994
- strcpy(zClass,"smc-"); /* common prefix for submenu controls */
994
+ fossil_strcpy(zClass,"smc-"); /* common prefix for submenu controls */
995995
for(i=0; i<nSubmenuCtrl; i++){
996996
const char *zQPN = aSubmenuCtrl[i].zName;
997997
const char *zDisabled = "";
998998
const char *zXtraClass = "";
999999
if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
@@ -1355,11 +1355,11 @@
13551355
** WEBPAGE: honeypot
13561356
** This page is a honeypot for spiders and bots.
13571357
*/
13581358
void honeypot_page(void){
13591359
unsigned int uSeed = captcha_seed();
1360
- const char *zDecoded = captcha_decode(uSeed);
1360
+ const char *zDecoded = captcha_decode(uSeed, 0);
13611361
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
13621362
char *zCaptcha = captcha_render(zDecoded);
13631363
style_header("I think you are a robot");
13641364
@ <p>You seem like a robot.</p>
13651365
@
13661366
--- src/style.c
+++ src/style.c
@@ -989,11 +989,11 @@
989 }else{
990 @ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
991 }
992 }
993 }
994 strcpy(zClass,"smc-"); /* common prefix for submenu controls */
995 for(i=0; i<nSubmenuCtrl; i++){
996 const char *zQPN = aSubmenuCtrl[i].zName;
997 const char *zDisabled = "";
998 const char *zXtraClass = "";
999 if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
@@ -1355,11 +1355,11 @@
1355 ** WEBPAGE: honeypot
1356 ** This page is a honeypot for spiders and bots.
1357 */
1358 void honeypot_page(void){
1359 unsigned int uSeed = captcha_seed();
1360 const char *zDecoded = captcha_decode(uSeed);
1361 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
1362 char *zCaptcha = captcha_render(zDecoded);
1363 style_header("I think you are a robot");
1364 @ <p>You seem like a robot.</p>
1365 @
1366
--- src/style.c
+++ src/style.c
@@ -989,11 +989,11 @@
989 }else{
990 @ <a class="label sml-%s(zClass)" href="%h(p->zLink)">%h(p->zLabel)</a>
991 }
992 }
993 }
994 fossil_strcpy(zClass,"smc-"); /* common prefix for submenu controls */
995 for(i=0; i<nSubmenuCtrl; i++){
996 const char *zQPN = aSubmenuCtrl[i].zName;
997 const char *zDisabled = "";
998 const char *zXtraClass = "";
999 if( aSubmenuCtrl[i].eVisible & STYLE_DISABLED ){
@@ -1355,11 +1355,11 @@
1355 ** WEBPAGE: honeypot
1356 ** This page is a honeypot for spiders and bots.
1357 */
1358 void honeypot_page(void){
1359 unsigned int uSeed = captcha_seed();
1360 const char *zDecoded = captcha_decode(uSeed, 0);
1361 int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
1362 char *zCaptcha = captcha_render(zDecoded);
1363 style_header("I think you are a robot");
1364 @ <p>You seem like a robot.</p>
1365 @
1366
+6 -1
--- src/timeline.c
+++ src/timeline.c
@@ -2913,11 +2913,16 @@
29132913
if( cpOnly && showCherrypicks ){
29142914
blob_appendf(&desc, " that participate in a cherrypick merge");
29152915
tmFlags |= TIMELINE_CHPICK|TIMELINE_DISJOINT;
29162916
}
29172917
if( zUser ){
2918
- blob_appendf(&desc, " by user %h", zUser);
2918
+ if( g.perm.Admin ){
2919
+ blob_appendf(&desc, " by user <a href='%R/setup_uinfo?l=%h'>%h</a>",
2920
+ zUser, zUser);
2921
+ }else{
2922
+ blob_appendf(&desc, " by user %h", zUser);
2923
+ }
29192924
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
29202925
}
29212926
if( zTagSql ){
29222927
if( matchStyle==MS_EXACT || matchStyle==MS_BRLIST ){
29232928
if( related ){
29242929
--- src/timeline.c
+++ src/timeline.c
@@ -2913,11 +2913,16 @@
2913 if( cpOnly && showCherrypicks ){
2914 blob_appendf(&desc, " that participate in a cherrypick merge");
2915 tmFlags |= TIMELINE_CHPICK|TIMELINE_DISJOINT;
2916 }
2917 if( zUser ){
2918 blob_appendf(&desc, " by user %h", zUser);
 
 
 
 
 
2919 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2920 }
2921 if( zTagSql ){
2922 if( matchStyle==MS_EXACT || matchStyle==MS_BRLIST ){
2923 if( related ){
2924
--- src/timeline.c
+++ src/timeline.c
@@ -2913,11 +2913,16 @@
2913 if( cpOnly && showCherrypicks ){
2914 blob_appendf(&desc, " that participate in a cherrypick merge");
2915 tmFlags |= TIMELINE_CHPICK|TIMELINE_DISJOINT;
2916 }
2917 if( zUser ){
2918 if( g.perm.Admin ){
2919 blob_appendf(&desc, " by user <a href='%R/setup_uinfo?l=%h'>%h</a>",
2920 zUser, zUser);
2921 }else{
2922 blob_appendf(&desc, " by user %h", zUser);
2923 }
2924 tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
2925 }
2926 if( zTagSql ){
2927 if( matchStyle==MS_EXACT || matchStyle==MS_BRLIST ){
2928 if( related ){
2929
--- src/update.c
+++ src/update.c
@@ -616,10 +616,13 @@
616616
/*
617617
** Clean up the mid and pid VFILE entries. Then commit the changes.
618618
*/
619619
if( dryRunFlag ){
620620
db_end_transaction(1); /* With --dry-run, rollback changes */
621
+ fossil_warning("\nREMINDER: this was a dry run -"
622
+ " no files were actually changed "
623
+ "(checkout is still %.10s).", rid_to_uuid(vid));
621624
}else{
622625
char *zPwd;
623626
ensure_empty_dirs_created(1);
624627
sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
625628
file_rmdir_sql_function, 0, 0);
626629
--- src/update.c
+++ src/update.c
@@ -616,10 +616,13 @@
616 /*
617 ** Clean up the mid and pid VFILE entries. Then commit the changes.
618 */
619 if( dryRunFlag ){
620 db_end_transaction(1); /* With --dry-run, rollback changes */
 
 
 
621 }else{
622 char *zPwd;
623 ensure_empty_dirs_created(1);
624 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
625 file_rmdir_sql_function, 0, 0);
626
--- src/update.c
+++ src/update.c
@@ -616,10 +616,13 @@
616 /*
617 ** Clean up the mid and pid VFILE entries. Then commit the changes.
618 */
619 if( dryRunFlag ){
620 db_end_transaction(1); /* With --dry-run, rollback changes */
621 fossil_warning("\nREMINDER: this was a dry run -"
622 " no files were actually changed "
623 "(checkout is still %.10s).", rid_to_uuid(vid));
624 }else{
625 char *zPwd;
626 ensure_empty_dirs_created(1);
627 sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
628 file_rmdir_sql_function, 0, 0);
629
+4 -9
--- src/url.c
+++ src/url.c
@@ -21,16 +21,10 @@
2121
#include "url.h"
2222
#include <stdio.h>
2323
2424
#ifdef _WIN32
2525
#include <io.h>
26
-#ifndef isatty
27
-#define isatty(d) _isatty(d)
28
-#endif
29
-#ifndef fileno
30
-#define fileno(s) _fileno(s)
31
-#endif
3226
#endif
3327
3428
#if INTERFACE
3529
/*
3630
** Flags for url_parse()
@@ -324,11 +318,12 @@
324318
blob_reset(&cfile);
325319
}else if( pUrlData->user!=0 && pUrlData->passwd==0
326320
&& (urlFlags & URL_PROMPT_PW)!=0 ){
327321
url_prompt_for_password_local(pUrlData);
328322
}else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
329
- if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){
323
+ if( fossil_isatty(fossil_fileno(stdin))
324
+ && ( urlFlags & URL_REMEMBER_PW )==0 ){
330325
if( save_password_prompt(pUrlData->passwd) ){
331326
pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
332327
}else{
333328
pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
334329
}
@@ -735,11 +730,11 @@
735730
** the provided UrlData structure. Store the result into the "passwd" member
736731
** of the provided UrlData structure.
737732
*/
738733
void url_prompt_for_password_local(UrlData *pUrlData){
739734
if( pUrlData->isSsh || pUrlData->isFile ) return;
740
- if( isatty(fileno(stdin))
735
+ if( fossil_isatty(fossil_fileno(stdin))
741736
&& (pUrlData->flags & URL_PROMPT_PW)!=0
742737
&& (pUrlData->flags & URL_PROMPTED)==0
743738
){
744739
pUrlData->flags |= URL_PROMPTED;
745740
pUrlData->passwd = prompt_for_user_password(pUrlData->canonical);
@@ -796,11 +791,11 @@
796791
** URL but no password.
797792
*/
798793
void url_get_password_if_needed(void){
799794
if( (g.url.user && g.url.user[0])
800795
&& (g.url.passwd==0 || g.url.passwd[0]==0)
801
- && isatty(fileno(stdin))
796
+ && fossil_isatty(fossil_fileno(stdin))
802797
){
803798
url_prompt_for_password();
804799
}
805800
}
806801
807802
--- src/url.c
+++ src/url.c
@@ -21,16 +21,10 @@
21 #include "url.h"
22 #include <stdio.h>
23
24 #ifdef _WIN32
25 #include <io.h>
26 #ifndef isatty
27 #define isatty(d) _isatty(d)
28 #endif
29 #ifndef fileno
30 #define fileno(s) _fileno(s)
31 #endif
32 #endif
33
34 #if INTERFACE
35 /*
36 ** Flags for url_parse()
@@ -324,11 +318,12 @@
324 blob_reset(&cfile);
325 }else if( pUrlData->user!=0 && pUrlData->passwd==0
326 && (urlFlags & URL_PROMPT_PW)!=0 ){
327 url_prompt_for_password_local(pUrlData);
328 }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
329 if( isatty(fileno(stdin)) && ( urlFlags & URL_REMEMBER_PW )==0 ){
 
330 if( save_password_prompt(pUrlData->passwd) ){
331 pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
332 }else{
333 pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
334 }
@@ -735,11 +730,11 @@
735 ** the provided UrlData structure. Store the result into the "passwd" member
736 ** of the provided UrlData structure.
737 */
738 void url_prompt_for_password_local(UrlData *pUrlData){
739 if( pUrlData->isSsh || pUrlData->isFile ) return;
740 if( isatty(fileno(stdin))
741 && (pUrlData->flags & URL_PROMPT_PW)!=0
742 && (pUrlData->flags & URL_PROMPTED)==0
743 ){
744 pUrlData->flags |= URL_PROMPTED;
745 pUrlData->passwd = prompt_for_user_password(pUrlData->canonical);
@@ -796,11 +791,11 @@
796 ** URL but no password.
797 */
798 void url_get_password_if_needed(void){
799 if( (g.url.user && g.url.user[0])
800 && (g.url.passwd==0 || g.url.passwd[0]==0)
801 && isatty(fileno(stdin))
802 ){
803 url_prompt_for_password();
804 }
805 }
806
807
--- src/url.c
+++ src/url.c
@@ -21,16 +21,10 @@
21 #include "url.h"
22 #include <stdio.h>
23
24 #ifdef _WIN32
25 #include <io.h>
 
 
 
 
 
 
26 #endif
27
28 #if INTERFACE
29 /*
30 ** Flags for url_parse()
@@ -324,11 +318,12 @@
318 blob_reset(&cfile);
319 }else if( pUrlData->user!=0 && pUrlData->passwd==0
320 && (urlFlags & URL_PROMPT_PW)!=0 ){
321 url_prompt_for_password_local(pUrlData);
322 }else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
323 if( fossil_isatty(fossil_fileno(stdin))
324 && ( urlFlags & URL_REMEMBER_PW )==0 ){
325 if( save_password_prompt(pUrlData->passwd) ){
326 pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
327 }else{
328 pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
329 }
@@ -735,11 +730,11 @@
730 ** the provided UrlData structure. Store the result into the "passwd" member
731 ** of the provided UrlData structure.
732 */
733 void url_prompt_for_password_local(UrlData *pUrlData){
734 if( pUrlData->isSsh || pUrlData->isFile ) return;
735 if( fossil_isatty(fossil_fileno(stdin))
736 && (pUrlData->flags & URL_PROMPT_PW)!=0
737 && (pUrlData->flags & URL_PROMPTED)==0
738 ){
739 pUrlData->flags |= URL_PROMPTED;
740 pUrlData->passwd = prompt_for_user_password(pUrlData->canonical);
@@ -796,11 +791,11 @@
791 ** URL but no password.
792 */
793 void url_get_password_if_needed(void){
794 if( (g.url.user && g.url.user[0])
795 && (g.url.passwd==0 || g.url.passwd[0]==0)
796 && fossil_isatty(fossil_fileno(stdin))
797 ){
798 url_prompt_for_password();
799 }
800 }
801
802
+51
--- src/util.c
+++ src/util.c
@@ -28,19 +28,42 @@
2828
/*
2929
** For the fossil_timer_xxx() family of functions...
3030
*/
3131
#ifdef _WIN32
3232
# include <windows.h>
33
+# include <io.h>
3334
#else
3435
# include <sys/time.h>
3536
# include <sys/resource.h>
3637
# include <sys/types.h>
3738
# include <sys/stat.h>
3839
# include <unistd.h>
3940
# include <fcntl.h>
4041
# include <errno.h>
4142
#endif
43
+
44
+/*
45
+** Returns the same as the platform's isatty() or _isatty() function.
46
+*/
47
+int fossil_isatty(int fd){
48
+#ifdef _WIN32
49
+ return _isatty(fd);
50
+#else
51
+ return isatty(fd);
52
+#endif
53
+}
54
+
55
+/*
56
+** Returns the same as the platform's fileno() or _fileno() function.
57
+*/
58
+int fossil_fileno(FILE *p){
59
+#ifdef _WIN32
60
+ return _fileno(p);
61
+#else
62
+ return fileno(p);
63
+#endif
64
+}
4265
4366
/*
4467
** Exit. Take care to close the database first.
4568
*/
4669
NORETURN void fossil_exit(int rc){
@@ -148,10 +171,38 @@
148171
}
149172
#else
150173
fossil_free(p);
151174
#endif
152175
}
176
+
177
+/*
178
+** Duplicate a string.
179
+*/
180
+char *fossil_strndup(const char *zOrig, ssize_t len){
181
+ char *z = 0;
182
+ if( zOrig ){
183
+ if( len<0 ) len = strlen(zOrig);
184
+ z = fossil_malloc( len+1 );
185
+ memcpy(z, zOrig, len);
186
+ z[len] = 0;
187
+ }
188
+ return z;
189
+}
190
+char *fossil_strdup(const char *zOrig){
191
+ return fossil_strndup(zOrig, -1);
192
+}
193
+char *fossil_strdup_nn(const char *zOrig){
194
+ if( zOrig==0 ) return fossil_strndup("", 0);
195
+ return fossil_strndup(zOrig, -1);
196
+}
197
+
198
+/*
199
+** strcpy() workalike to squelch an unwarranted warning from OpenBSD.
200
+*/
201
+void fossil_strcpy(char *dest, const char *src){
202
+ while( (*(dest++) = *(src++))!=0 ){}
203
+}
153204
154205
/*
155206
** Translate every upper-case character in the input string into
156207
** its equivalent lower-case.
157208
*/
158209
--- src/util.c
+++ src/util.c
@@ -28,19 +28,42 @@
28 /*
29 ** For the fossil_timer_xxx() family of functions...
30 */
31 #ifdef _WIN32
32 # include <windows.h>
 
33 #else
34 # include <sys/time.h>
35 # include <sys/resource.h>
36 # include <sys/types.h>
37 # include <sys/stat.h>
38 # include <unistd.h>
39 # include <fcntl.h>
40 # include <errno.h>
41 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
43 /*
44 ** Exit. Take care to close the database first.
45 */
46 NORETURN void fossil_exit(int rc){
@@ -148,10 +171,38 @@
148 }
149 #else
150 fossil_free(p);
151 #endif
152 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
154 /*
155 ** Translate every upper-case character in the input string into
156 ** its equivalent lower-case.
157 */
158
--- src/util.c
+++ src/util.c
@@ -28,19 +28,42 @@
28 /*
29 ** For the fossil_timer_xxx() family of functions...
30 */
31 #ifdef _WIN32
32 # include <windows.h>
33 # include <io.h>
34 #else
35 # include <sys/time.h>
36 # include <sys/resource.h>
37 # include <sys/types.h>
38 # include <sys/stat.h>
39 # include <unistd.h>
40 # include <fcntl.h>
41 # include <errno.h>
42 #endif
43
44 /*
45 ** Returns the same as the platform's isatty() or _isatty() function.
46 */
47 int fossil_isatty(int fd){
48 #ifdef _WIN32
49 return _isatty(fd);
50 #else
51 return isatty(fd);
52 #endif
53 }
54
55 /*
56 ** Returns the same as the platform's fileno() or _fileno() function.
57 */
58 int fossil_fileno(FILE *p){
59 #ifdef _WIN32
60 return _fileno(p);
61 #else
62 return fileno(p);
63 #endif
64 }
65
66 /*
67 ** Exit. Take care to close the database first.
68 */
69 NORETURN void fossil_exit(int rc){
@@ -148,10 +171,38 @@
171 }
172 #else
173 fossil_free(p);
174 #endif
175 }
176
177 /*
178 ** Duplicate a string.
179 */
180 char *fossil_strndup(const char *zOrig, ssize_t len){
181 char *z = 0;
182 if( zOrig ){
183 if( len<0 ) len = strlen(zOrig);
184 z = fossil_malloc( len+1 );
185 memcpy(z, zOrig, len);
186 z[len] = 0;
187 }
188 return z;
189 }
190 char *fossil_strdup(const char *zOrig){
191 return fossil_strndup(zOrig, -1);
192 }
193 char *fossil_strdup_nn(const char *zOrig){
194 if( zOrig==0 ) return fossil_strndup("", 0);
195 return fossil_strndup(zOrig, -1);
196 }
197
198 /*
199 ** strcpy() workalike to squelch an unwarranted warning from OpenBSD.
200 */
201 void fossil_strcpy(char *dest, const char *src){
202 while( (*(dest++) = *(src++))!=0 ){}
203 }
204
205 /*
206 ** Translate every upper-case character in the input string into
207 ** its equivalent lower-case.
208 */
209
+14 -5
--- src/xfer.c
+++ src/xfer.c
@@ -1989,10 +1989,11 @@
19891989
sqlite3_int64 mtime; /* Modification time on a UV file */
19901990
int autopushFailed = 0; /* Autopush following commit failed if true */
19911991
const char *zCkinLock; /* Name of check-in to lock. NULL for none */
19921992
const char *zClientId; /* A unique identifier for this check-out */
19931993
unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */
1994
+ const int bOutIsTty = fossil_isatty(fossil_fileno(stdout));
19941995
19951996
if( pnRcvd ) *pnRcvd = 0;
19961997
if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
19971998
if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
19981999
&& configRcvMask==0
@@ -2304,12 +2305,14 @@
23042305
blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
23052306
xfer.nFileSent, xfer.nDeltaSent);
23062307
}else{
23072308
nRoundtrip++;
23082309
nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
2309
- fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2310
- nRoundtrip, nArtifactSent, nArtifactRcvd);
2310
+ if( bOutIsTty!=0 ){
2311
+ fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2312
+ nRoundtrip, nArtifactSent, nArtifactRcvd);
2313
+ }
23112314
}
23122315
nCardSent = 0;
23132316
nCardRcvd = 0;
23142317
xfer.nFileSent = 0;
23152318
xfer.nDeltaSent = 0;
@@ -2805,12 +2808,14 @@
28052808
if( nCardRcvd>0 && (syncFlags & SYNC_VERBOSE) ){
28062809
fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Received:",
28072810
blob_size(&recv), nCardRcvd,
28082811
xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
28092812
}else{
2810
- fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2811
- nRoundtrip, nArtifactSent, nArtifactRcvd);
2813
+ if( bOutIsTty!=0 ){
2814
+ fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2815
+ nRoundtrip, nArtifactSent, nArtifactRcvd);
2816
+ }
28122817
}
28132818
nUncRcvd += blob_size(&recv);
28142819
blob_reset(&recv);
28152820
nCycle++;
28162821
@@ -2864,11 +2869,15 @@
28642869
}else if( rSkew*24.0*3600.0 < -10.0 ){
28652870
fossil_warning("*** time skew *** server is slow by %s",
28662871
db_timespan_name(-rSkew));
28672872
g.clockSkewSeen = 1;
28682873
}
2869
-
2874
+ if( bOutIsTty==0 ){
2875
+ fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2876
+ nRoundtrip, nArtifactSent, nArtifactRcvd);
2877
+ fossil_force_newline();
2878
+ }
28702879
fossil_force_newline();
28712880
if( g.zHttpCmd==0 ){
28722881
if( syncFlags & SYNC_VERBOSE ){
28732882
fossil_print(
28742883
"%s done, wire bytes sent: %lld received: %lld remote: %s%s\n",
28752884
--- src/xfer.c
+++ src/xfer.c
@@ -1989,10 +1989,11 @@
1989 sqlite3_int64 mtime; /* Modification time on a UV file */
1990 int autopushFailed = 0; /* Autopush following commit failed if true */
1991 const char *zCkinLock; /* Name of check-in to lock. NULL for none */
1992 const char *zClientId; /* A unique identifier for this check-out */
1993 unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */
 
1994
1995 if( pnRcvd ) *pnRcvd = 0;
1996 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1997 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1998 && configRcvMask==0
@@ -2304,12 +2305,14 @@
2304 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
2305 xfer.nFileSent, xfer.nDeltaSent);
2306 }else{
2307 nRoundtrip++;
2308 nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
2309 fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2310 nRoundtrip, nArtifactSent, nArtifactRcvd);
 
 
2311 }
2312 nCardSent = 0;
2313 nCardRcvd = 0;
2314 xfer.nFileSent = 0;
2315 xfer.nDeltaSent = 0;
@@ -2805,12 +2808,14 @@
2805 if( nCardRcvd>0 && (syncFlags & SYNC_VERBOSE) ){
2806 fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Received:",
2807 blob_size(&recv), nCardRcvd,
2808 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
2809 }else{
2810 fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2811 nRoundtrip, nArtifactSent, nArtifactRcvd);
 
 
2812 }
2813 nUncRcvd += blob_size(&recv);
2814 blob_reset(&recv);
2815 nCycle++;
2816
@@ -2864,11 +2869,15 @@
2864 }else if( rSkew*24.0*3600.0 < -10.0 ){
2865 fossil_warning("*** time skew *** server is slow by %s",
2866 db_timespan_name(-rSkew));
2867 g.clockSkewSeen = 1;
2868 }
2869
 
 
 
 
2870 fossil_force_newline();
2871 if( g.zHttpCmd==0 ){
2872 if( syncFlags & SYNC_VERBOSE ){
2873 fossil_print(
2874 "%s done, wire bytes sent: %lld received: %lld remote: %s%s\n",
2875
--- src/xfer.c
+++ src/xfer.c
@@ -1989,10 +1989,11 @@
1989 sqlite3_int64 mtime; /* Modification time on a UV file */
1990 int autopushFailed = 0; /* Autopush following commit failed if true */
1991 const char *zCkinLock; /* Name of check-in to lock. NULL for none */
1992 const char *zClientId; /* A unique identifier for this check-out */
1993 unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */
1994 const int bOutIsTty = fossil_isatty(fossil_fileno(stdout));
1995
1996 if( pnRcvd ) *pnRcvd = 0;
1997 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1998 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1999 && configRcvMask==0
@@ -2304,12 +2305,14 @@
2305 blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
2306 xfer.nFileSent, xfer.nDeltaSent);
2307 }else{
2308 nRoundtrip++;
2309 nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
2310 if( bOutIsTty!=0 ){
2311 fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2312 nRoundtrip, nArtifactSent, nArtifactRcvd);
2313 }
2314 }
2315 nCardSent = 0;
2316 nCardRcvd = 0;
2317 xfer.nFileSent = 0;
2318 xfer.nDeltaSent = 0;
@@ -2805,12 +2808,14 @@
2808 if( nCardRcvd>0 && (syncFlags & SYNC_VERBOSE) ){
2809 fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Received:",
2810 blob_size(&recv), nCardRcvd,
2811 xfer.nFileRcvd, xfer.nDeltaRcvd + xfer.nDanglingFile);
2812 }else{
2813 if( bOutIsTty!=0 ){
2814 fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2815 nRoundtrip, nArtifactSent, nArtifactRcvd);
2816 }
2817 }
2818 nUncRcvd += blob_size(&recv);
2819 blob_reset(&recv);
2820 nCycle++;
2821
@@ -2864,11 +2869,15 @@
2869 }else if( rSkew*24.0*3600.0 < -10.0 ){
2870 fossil_warning("*** time skew *** server is slow by %s",
2871 db_timespan_name(-rSkew));
2872 g.clockSkewSeen = 1;
2873 }
2874 if( bOutIsTty==0 ){
2875 fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
2876 nRoundtrip, nArtifactSent, nArtifactRcvd);
2877 fossil_force_newline();
2878 }
2879 fossil_force_newline();
2880 if( g.zHttpCmd==0 ){
2881 if( syncFlags & SYNC_VERBOSE ){
2882 fossil_print(
2883 "%s done, wire bytes sent: %lld received: %lld remote: %s%s\n",
2884
--- tools/makeheaders.c
+++ tools/makeheaders.c
@@ -3166,10 +3166,15 @@
31663166
31673167
/* Done!
31683168
*/
31693169
return pFile;
31703170
}
3171
+
3172
+/* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
3173
+static void local_strcpy(char *dest, const char *src){
3174
+ while( (*(dest++) = *(src++))!=0 ){}
3175
+}
31713176
31723177
/* MS-Windows and MS-DOS both have the following serious OS bug: the
31733178
** length of a command line is severely restricted. But this program
31743179
** occasionally requires long command lines. Hence the following
31753180
** work around.
@@ -3243,11 +3248,11 @@
32433248
}
32443249
if( zNew ){
32453250
int j = nNew + index;
32463251
zNew[j] = malloc( n + 1 );
32473252
if( zNew[j] ){
3248
- strcpy( zNew[j], zBuf );
3253
+ local_strcpy( zNew[j], zBuf );
32493254
}
32503255
}
32513256
}
32523257
}
32533258
fclose(in);
32543259
--- tools/makeheaders.c
+++ tools/makeheaders.c
@@ -3166,10 +3166,15 @@
3166
3167 /* Done!
3168 */
3169 return pFile;
3170 }
 
 
 
 
 
3171
3172 /* MS-Windows and MS-DOS both have the following serious OS bug: the
3173 ** length of a command line is severely restricted. But this program
3174 ** occasionally requires long command lines. Hence the following
3175 ** work around.
@@ -3243,11 +3248,11 @@
3243 }
3244 if( zNew ){
3245 int j = nNew + index;
3246 zNew[j] = malloc( n + 1 );
3247 if( zNew[j] ){
3248 strcpy( zNew[j], zBuf );
3249 }
3250 }
3251 }
3252 }
3253 fclose(in);
3254
--- tools/makeheaders.c
+++ tools/makeheaders.c
@@ -3166,10 +3166,15 @@
3166
3167 /* Done!
3168 */
3169 return pFile;
3170 }
3171
3172 /* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
3173 static void local_strcpy(char *dest, const char *src){
3174 while( (*(dest++) = *(src++))!=0 ){}
3175 }
3176
3177 /* MS-Windows and MS-DOS both have the following serious OS bug: the
3178 ** length of a command line is severely restricted. But this program
3179 ** occasionally requires long command lines. Hence the following
3180 ** work around.
@@ -3243,11 +3248,11 @@
3248 }
3249 if( zNew ){
3250 int j = nNew + index;
3251 zNew[j] = malloc( n + 1 );
3252 if( zNew[j] ){
3253 local_strcpy( zNew[j], zBuf );
3254 }
3255 }
3256 }
3257 }
3258 fclose(in);
3259
+6 -1
--- tools/mkindex.c
+++ tools/mkindex.c
@@ -327,10 +327,15 @@
327327
while( fossil_isspace(z[0]) ) z++;
328328
len = (int)strlen(z);
329329
while( len>0 && fossil_isspace(z[len-1]) ){ len--; }
330330
aEntry[nUsed-1].zDflt = string_dup(z,len);
331331
}
332
+
333
+/* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
334
+static void local_strcpy(char *dest, const char *src){
335
+ while( (*(dest++) = *(src++))!=0 ){}
336
+}
332337
333338
/*
334339
** Scan a line for a function that implements a web page or command.
335340
*/
336341
void scan_for_func(char *zLine){
@@ -349,11 +354,11 @@
349354
){
350355
if( zLine[2]=='\n' ){
351356
zHelp[nHelp++] = '\n';
352357
}else{
353358
if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
354
- strcpy(&zHelp[nHelp], &zLine[3]);
359
+ local_strcpy(&zHelp[nHelp], &zLine[3]);
355360
nHelp += strlen(&zHelp[nHelp]);
356361
}
357362
return;
358363
}
359364
for(i=0; fossil_isspace(zLine[i]); i++){}
360365
--- tools/mkindex.c
+++ tools/mkindex.c
@@ -327,10 +327,15 @@
327 while( fossil_isspace(z[0]) ) z++;
328 len = (int)strlen(z);
329 while( len>0 && fossil_isspace(z[len-1]) ){ len--; }
330 aEntry[nUsed-1].zDflt = string_dup(z,len);
331 }
 
 
 
 
 
332
333 /*
334 ** Scan a line for a function that implements a web page or command.
335 */
336 void scan_for_func(char *zLine){
@@ -349,11 +354,11 @@
349 ){
350 if( zLine[2]=='\n' ){
351 zHelp[nHelp++] = '\n';
352 }else{
353 if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
354 strcpy(&zHelp[nHelp], &zLine[3]);
355 nHelp += strlen(&zHelp[nHelp]);
356 }
357 return;
358 }
359 for(i=0; fossil_isspace(zLine[i]); i++){}
360
--- tools/mkindex.c
+++ tools/mkindex.c
@@ -327,10 +327,15 @@
327 while( fossil_isspace(z[0]) ) z++;
328 len = (int)strlen(z);
329 while( len>0 && fossil_isspace(z[len-1]) ){ len--; }
330 aEntry[nUsed-1].zDflt = string_dup(z,len);
331 }
332
333 /* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
334 static void local_strcpy(char *dest, const char *src){
335 while( (*(dest++) = *(src++))!=0 ){}
336 }
337
338 /*
339 ** Scan a line for a function that implements a web page or command.
340 */
341 void scan_for_func(char *zLine){
@@ -349,11 +354,11 @@
354 ){
355 if( zLine[2]=='\n' ){
356 zHelp[nHelp++] = '\n';
357 }else{
358 if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0;
359 local_strcpy(&zHelp[nHelp], &zLine[3]);
360 nHelp += strlen(&zHelp[nHelp]);
361 }
362 return;
363 }
364 for(i=0; fossil_isspace(zLine[i]); i++){}
365
--- tools/mkversion.c
+++ tools/mkversion.c
@@ -81,10 +81,15 @@
8181
zOut[n] = "0123456789abcdef"[(t>>4)&0xf];
8282
zOut[n+1] = "0123456789abcdef"[t&0xf];
8383
}
8484
zOut[n] = 0;
8585
}
86
+
87
+/* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
88
+static void local_strcpy(char *dest, const char *src){
89
+ while( (*(dest++) = *(src++))!=0 ){}
90
+}
8691
8792
int main(int argc, char *argv[]){
8893
FILE *m,*u,*v;
8994
char *z;
9095
#if defined(__DMC__) /* e.g. 0x857 */
@@ -173,11 +178,11 @@
173178
z++;
174179
}
175180
for(z=vx; z[0]=='0'; z++){}
176181
printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]);
177182
memset(vx,0,sizeof(vx));
178
- strcpy(vx,b);
183
+ local_strcpy(vx,b);
179184
for(z=vx; z[0]; z++){
180185
if( z[0]=='-' ){
181186
z[0] = 0;
182187
break;
183188
}
184189
--- tools/mkversion.c
+++ tools/mkversion.c
@@ -81,10 +81,15 @@
81 zOut[n] = "0123456789abcdef"[(t>>4)&0xf];
82 zOut[n+1] = "0123456789abcdef"[t&0xf];
83 }
84 zOut[n] = 0;
85 }
 
 
 
 
 
86
87 int main(int argc, char *argv[]){
88 FILE *m,*u,*v;
89 char *z;
90 #if defined(__DMC__) /* e.g. 0x857 */
@@ -173,11 +178,11 @@
173 z++;
174 }
175 for(z=vx; z[0]=='0'; z++){}
176 printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]);
177 memset(vx,0,sizeof(vx));
178 strcpy(vx,b);
179 for(z=vx; z[0]; z++){
180 if( z[0]=='-' ){
181 z[0] = 0;
182 break;
183 }
184
--- tools/mkversion.c
+++ tools/mkversion.c
@@ -81,10 +81,15 @@
81 zOut[n] = "0123456789abcdef"[(t>>4)&0xf];
82 zOut[n+1] = "0123456789abcdef"[t&0xf];
83 }
84 zOut[n] = 0;
85 }
86
87 /* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
88 static void local_strcpy(char *dest, const char *src){
89 while( (*(dest++) = *(src++))!=0 ){}
90 }
91
92 int main(int argc, char *argv[]){
93 FILE *m,*u,*v;
94 char *z;
95 #if defined(__DMC__) /* e.g. 0x857 */
@@ -173,11 +178,11 @@
178 z++;
179 }
180 for(z=vx; z[0]=='0'; z++){}
181 printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]);
182 memset(vx,0,sizeof(vx));
183 local_strcpy(vx,b);
184 for(z=vx; z[0]; z++){
185 if( z[0]=='-' ){
186 z[0] = 0;
187 break;
188 }
189

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button